AmendHub

Download

cyberslak

/

lightsout

/

main.c

 

(View History)

cyberslak   Properly check for Thread Manager before using it Latest amendment: 25 on 2025-04-21

1 // SPDX-License-Identifier: MIT
2
3 #include <stdlib.h>
4 #include <string.h>
5 #include <stdio.h>
6 #include <unistd.h>
7 #include "util.h"
8 #include "net.h"
9 #include "ha.h"
10 #include "list.h"
11 #include "slider.h"
12 #include "preferences.h"
13 #include "entity_ldef.h"
14
15 #define kScrollBarWidth 15
16 #define kSliderCDEFId 128
17 #define kEntityLDEFId 128
18 #define kCustomSliderProc (16 * kSliderCDEFId)
19 #define kCustomListProc (kEntityLDEFId)
20 #define kBarUpdateRate (1 * 60) // 1 second(s)
21 #define kBarWidth 100
22 #define kCtrlWidth 40
23 #define kCtrlHeight 80
24 #define kCtrlPad ((kBarWidth - kCtrlWidth) / 2)
25
26 #define kEntityListDialog 128
27
28 #define mApple 128
29 #define mFile 129
30 #define mEdit 130
31
32 #define miAbout 1
33 #define miEntityAdd 1
34 #define miQuit 3
35 #define miClear 4
36
37 /* GLOBALS */
38 Boolean gRunning = true;
39 short gNumBars = 0;
40 Boolean gHaveScrollBar = false;
41
42 Handle gSliderCDEF, gEntityLDEF;
43 PrefHandle gPreferences;
44 MenuHandle gEditMenu;
45
46 Pattern gSliderPattern, gBackPattern;
47
48 WindowPtr gMainWindow = NULL;
49 list_t gEntities = LIST_INIT(gEntities);
50
51 /* PROTOTYPES */
52 void ensure_valid_prefs(void);
53 void dialog_info_free(struct dialog_info *dinfo);
54 void entity_list_add(struct dialog_info *dinfo);
55 void entity_list_mousedown(EventRecord* evt, WindowPtr win);
56 void entity_list_activate(bool activate, WindowPtr win);
57 void entity_list_show(void);
58 void event_loop(void);
59 void event_update(WindowPtr win);
60 void event_activate(bool activate, EventRecord* evt, WindowPtr win);
61 void event_mousedown(EventRecord*, WindowPtr, short);
62
63 void menu_init(void);
64 void menu_click(long);
65
66 void lightsout_init(Handle previousEnts);
67 void bar_create(WindowPtr win, const char* id);
68
69 void resolve_slider_cdef();
70 void resolve_entity_ldef();
71
72 pascal void dialog_list_update(WindowPtr theWin, short itemNo);
73
74 void bar_draw(struct entity*);
75 void bars_draw();
76 void draw_background();
77 void bars_update();
78
79 void scrollbar_create(WindowPtr win);
80 void scrollbar_remove(WindowPtr win);
81
82 void update_entity_positions(short scrollValue);
83 void get_entity_bounds(struct entity *ent, Rect* out);
84
85 struct dialog_info
86 {
87 ListHandle lHnd;
88 struct list ents;
89 void (*handle_mousedown)(EventRecord*, WindowPtr);
90 void (*handle_activate)(bool activate, WindowPtr);
91 };
92
93 struct window_info
94 {
95 ControlHandle scrollBar;
96 };
97
98 enum control_type
99 {
100 CONTROL_SLIDER,
101 CONTROL_SCROLLBAR,
102 };
103
104 void ensure_valid_prefs(void)
105 {
106 bool updatedPrefs = false;
107
108 gPreferences = preferences_load();
109
110 while (ha_test_prefs() != 0)
111 {
112 info("Server configuration is invalid; "
113 "please review your settings.");
114
115 // preferences invalid; show preferences dialog
116 if (preferences_dialog() != 0)
117 {
118 ExitToShell();
119 } else {
120 updatedPrefs = true;
121 }
122 }
123
124 if (updatedPrefs)
125 preferences_save(gPreferences);
126 }
127
128 int main()
129 {
130 toolbox_init();
131 memory_init();
132
133 net_init();
134
135 resolve_slider_cdef();
136 resolve_entity_ldef();
137 GetIndPattern(&gSliderPattern, 0, 22);
138 GetIndPattern(&gBackPattern, 0, 3);
139
140 menu_init();
141
142 ensure_valid_prefs();
143
144 lightsout_init(preferences_get_entities());
145 event_loop();
146
147 net_fini();
148
149 preferences_save_entities(&gEntities);
150
151 return 0;
152 }
153
154 void resolve_slider_cdef()
155 {
156 def_jmp_t* slider_cdef;
157 gSliderCDEF = GetResource('CDEF', 128);
158 HLock(gSliderCDEF);
159
160 slider_cdef = (def_jmp_t*)*gSliderCDEF;
161 slider_cdef->addr = slider_proc;
162 }
163
164 void resolve_entity_ldef()
165 {
166 def_jmp_t* entity_ldef;
167 gEntityLDEF = GetResource('LDEF', 128);
168 HLock(gEntityLDEF);
169
170 entity_ldef = (def_jmp_t*)*gEntityLDEF;
171 entity_ldef->addr = entity_ldef_proc;
172 }
173
174 void scrollbar_create(WindowPtr win)
175 {
176 struct window_info *info = (void*)GetWRefCon(win);
177 Rect sbRect;
178 short winHeight = rect_height(&win->portRect);
179 short winWidth = rect_width(&win->portRect);
180
181 sbRect.top = winHeight - kScrollBarWidth;
182 sbRect.left = -1;
183 sbRect.right = winWidth + 1;
184 sbRect.bottom = winHeight + 1;
185
186 info->scrollBar = NewControl(win,
187 &sbRect,
188 (u8*)"",
189 true,
190 0,
191 0,
192 1,
193 scrollBarProc,
194 CONTROL_SCROLLBAR);
195 }
196
197 void scrollbar_remove(WindowPtr win)
198 {
199 struct window_info *info = (void*)GetWRefCon(win);
200
201 if (info->scrollBar)
202 {
203 DisposeControl(info->scrollBar);
204 info->scrollBar = NULL;
205 }
206 }
207
208 void handle_scrollbar(WindowPtr win)
209 {
210 short width = rect_width(&win->portRect);
211 short height = rect_height(&win->portRect);
212 if (gNumBars > 3 && !gHaveScrollBar)
213 {
214 SizeWindow(win, width, height + kScrollBarWidth, true);
215 scrollbar_create(win);
216 gHaveScrollBar = true;
217 } else if (gNumBars > 3)
218 {
219 struct window_info *info = (void*)GetWRefCon(win);
220 SetControlMaximum(info->scrollBar, gNumBars - 3);
221 }
222
223 if (gNumBars <= 3 && gHaveScrollBar)
224 {
225 SizeWindow(win, width, height - kScrollBarWidth, true);
226 scrollbar_remove(win);
227 gHaveScrollBar = false;
228 }
229 }
230
231 void bar_create(WindowPtr win, const char* id)
232 {
233 struct entity* ent = xmalloc(sizeof(struct entity));
234 Rect controlPos;
235 Rect updateBounds;
236
237 short winHeight;
238 short barOffset = gNumBars * kBarWidth;
239
240 snprintf(ent->id, 128, "%s", id);
241
242 winHeight = rect_height(&win->portRect);
243 winHeight -= (gHaveScrollBar ? kScrollBarWidth : 0);
244
245 controlPos.top = (winHeight - kCtrlHeight)/2;
246 controlPos.bottom = controlPos.top + kCtrlHeight;
247 controlPos.left = barOffset + kCtrlPad;
248 controlPos.right = controlPos.left + kCtrlWidth;
249
250 ha_get_entity_state(ent->id, &ent->state);
251
252 ent->ctrl = NewControl(
253 win,
254 &controlPos,
255 nil,
256 true,
257 ent->state.brightness, // current value
258 0, 255,
259 kCustomSliderProc,
260 CONTROL_SLIDER
261 );
262
263 ent->outerRgn = NewRgn();
264 ent->selected = false;
265
266 get_entity_bounds(ent, &updateBounds);
267
268 updateBounds.right += 2; // bg edge
269
270 list_add_tail(&gEntities, &ent->node);
271
272 gNumBars++;
273
274 barOffset += kBarWidth;
275
276 handle_scrollbar(win);
277
278 with_port(win, {
279 InvalRect(&updateBounds);
280 })
281 }
282
283 void bar_remove(WindowPtr win, struct entity *ent)
284 {
285 struct window_info *info = (void*)GetWRefCon(win);
286 short scrollValue = 0;
287 Rect barRect;
288
289 get_entity_bounds(ent, &barRect);
290
291 list_del(&ent->node);
292 DisposeControl(ent->ctrl);
293 DisposeRgn(ent->outerRgn);
294 free(ent);
295
296 // you can't just update the bar rect,
297 // because other bars might shift into the window area
298 with_port(win, {
299 InvalRect(&win->portRect);
300 })
301
302 gNumBars--;
303
304 handle_scrollbar(win);
305
306 if (info->scrollBar)
307 scrollValue = GetControlValue(info->scrollBar);
308
309 update_entity_positions(scrollValue);
310 }
311
312 /** Update a list in a dialog.
313 *
314 * Assumes the list is stored in the window reference of the
315 * dialog. Then calls LUpdate to update the list contents,
316 * and FrameRect to draw the border around the list.
317 */
318 pascal void dialog_list_update(WindowPtr theWin, short itemNo)
319 {
320 struct dialog_info *dinfo = (void*)GetWRefCon(theWin);
321 ListHandle lHnd = dinfo->lHnd;
322 Rect frameRect = (**lHnd).rView;
323 frameRect.right += kScrollBarWidth;
324 rect_expand(&frameRect, 1);
325
326 LUpdate(theWin->visRgn, lHnd);
327
328 FrameRect(&frameRect);
329 }
330
331 void dialog_info_free(struct dialog_info *dinfo)
332 {
333 list_t *node;
334 LDispose(dinfo->lHnd);
335
336 while ((node = list_pop(&dinfo->ents)) != NULL)
337 {
338 free(container_of(node, struct entity, node));
339 }
340
341 free(dinfo);
342 }
343
344 void entity_list_add(struct dialog_info* dinfo)
345 {
346 Point pt = {0, 0};
347 struct entity* ent;
348 if (LGetSelect(true, &pt, dinfo->lHnd))
349 {
350 short len = 4;
351 LGetCell(&ent, &len, pt, dinfo->lHnd);
352 bar_create(gMainWindow, ent->id);
353 }
354 }
355
356 void entity_list_mousedown(EventRecord* evt, WindowPtr win)
357 {
358 DialogPtr theDialog;
359 short itemHit;
360 struct dialog_info* dinfo = (void*)GetWRefCon(win);
361
362 with_port(win, {
363 DialogSelect(evt, &theDialog, &itemHit);
364
365 GlobalToLocal(&evt->where);
366
367 switch (itemHit)
368 {
369 case 1:
370 entity_list_add(dinfo);
371
372 // must dispose of list before dialog
373 dialog_info_free(dinfo);
374 DisposeDialog(theDialog);
375 break;
376 case 2:
377 LClick(evt->where, evt->modifiers, dinfo->lHnd);
378 break;
379 }
380 })
381 }
382
383 void entity_list_activate(bool activate, WindowPtr win)
384 {
385 struct dialog_info *dinfo = (void*)GetWRefCon(win);
386 LActivate(activate, dinfo->lHnd);
387 }
388
389 /* Open the entity selection dialog. */
390 void entity_list_show()
391 {
392 short type;
393 Handle itemHnd;
394 Rect itemRect, contentRect;
395 Rect dataBounds;
396 Point cSize = {0, 0};
397 Point pt = {0, 0};
398 ListHandle lHnd;
399 struct dialog_info *dinfo = xmalloc(sizeof(struct dialog_info));
400 struct entity *ent;
401 list_t *node;
402
403 short numEnts = ha_get_entities(&dinfo->ents);
404
405 DialogPtr dlog = GetNewDialog(
406 kEntityListDialog, nil, (WindowPtr)-1);
407
408 GetDialogItem(dlog, 2, &type, &itemHnd, &itemRect);
409 SetDialogItem(dlog, 2, type, (Handle)dialog_list_update, &itemRect);
410
411 contentRect = itemRect;
412 contentRect.right -= kScrollBarWidth;
413
414 rect_expand(&itemRect, 1);
415
416 SetRect(&dataBounds, 0, 0, 1, 0);
417 lHnd = LNew(&contentRect, &dataBounds, cSize, kCustomListProc,
418 dlog, true, false, false, true);
419
420 // todo allow multiple selections
421 (**lHnd).selFlags |= lOnlyOne;
422
423 dinfo->lHnd = lHnd;
424 dinfo->handle_mousedown = entity_list_mousedown;
425 dinfo->handle_activate = entity_list_activate;
426
427 SetWRefCon(dlog, (long)dinfo);
428
429 LAddRow(numEnts, 0, lHnd);
430
431 list_foreach(&dinfo->ents, node)
432 {
433 ent = container_of(node, struct entity, node);
434 LSetCell(&ent, sizeof(Ptr), pt, lHnd);
435 pt.v++;
436 }
437
438 ShowWindow(dlog);
439 }
440
441 void lightsout_init(Handle previousEnts)
442 {
443 WindowPtr win;
444 short controlWidth = 40;
445 short controlHeight = 80;
446 struct window_info *wi = xmalloc(sizeof(struct window_info));
447
448 win = GetNewCWindow(128, nil, (WindowPtr)-1);
449 SetWTitle(win, "\pLights Out");
450 SetWRefCon(win, (long)wi);
451
452 wi->scrollBar = NULL;
453
454 SetPort(win);
455
456 win_center(win);
457
458 gMainWindow = win;
459
460 if (previousEnts)
461 {
462 // previous entities are packed into the handle
463 // as consecutive NUL-terminated strings.
464 size_t sz = GetHandleSize(previousEnts);
465 size_t idx = 0;
466 size_t len = 0;
467 HLock(previousEnts);
468
469 while (idx < sz)
470 {
471 len = strlen(*previousEnts + idx);
472 bar_create(win, *previousEnts + idx);
473 idx += len + 1;
474 }
475
476 HUnlock(previousEnts);
477 }
478
479 ShowWindow(win);
480 }
481
482 void menu_init(void)
483 {
484 Handle menuBar = GetNewMBar(128);
485 MenuHandle appleMenu;
486 short i;
487
488 SetMenuBar(menuBar);
489
490 gEditMenu = GetMenuHandle(mEdit);
491
492 for (i = 1; i <= miClear; ++i)
493 DisableItem(gEditMenu, i);
494
495 appleMenu = GetMenuHandle(mApple);
496 AppendResMenu(appleMenu, 'DRVR');
497
498 DrawMenuBar();
499 }
500
501 bool menu_item_enabled(MenuHandle hnd, short itemId)
502 {
503 if (itemId < 32)
504 {
505 return (**hnd).enableFlags & (1 << itemId);
506 }
507 return (**hnd).enableFlags & 1;
508 }
509
510 void menu_update()
511 {
512 struct entity *ent;
513 list_t *node;
514 bool any_selected = false;
515 bool itemEnabled = menu_item_enabled(gEditMenu, miClear);
516
517 list_foreach(&gEntities, node)
518 {
519 ent = container_of(node, struct entity, node);
520 if (ent->selected)
521 any_selected = true;
522 }
523
524 if (any_selected && !itemEnabled)
525 {
526 EnableItem(gEditMenu, miClear);
527 }
528 else if (!any_selected && itemEnabled)
529 {
530 DisableItem(gEditMenu, miClear);
531 }
532 }
533
534 void menu_click(long menuChoice)
535 {
536 short menuId, itemId;
537 MenuHandle theMenu;
538 GrafPtr oldPort;
539 Str255 itemName;
540 menuId = HiWord(menuChoice);
541 itemId = LoWord(menuChoice);
542
543 switch (menuId)
544 {
545 case mApple:
546 if (itemId == miAbout)
547 {
548 info("LightsOut\r© 2025 Sam van Kampen");
549 } else
550 {
551 theMenu = GetMenuHandle(menuId);
552 GetMenuItemText(theMenu, itemId, itemName);
553 GetPort(&oldPort);
554 OpenDeskAcc(itemName);
555 SetPort(oldPort);
556 }
557 break;
558 case mFile:
559 if (itemId == miEntityAdd)
560 {
561 entity_list_show();
562 }
563 else if (itemId == miQuit)
564 {
565 gRunning = false;
566 }
567 break;
568 case mEdit:
569 if (itemId == miClear && FrontWindow() == gMainWindow)
570 {
571 struct entity *ent;
572 list_t *node, *prev;
573 list_foreach_safe_rev(&gEntities, node, prev)
574 {
575 ent = container_of(node, struct entity, node);
576 if (ent->selected)
577 bar_remove(gMainWindow, ent);
578 }
579 }
580 break;
581 }
582
583 HiliteMenu(0);
584 }
585
586 void get_entity_bounds(struct entity *ent, Rect* out)
587 {
588 Rect* sliderBounds;
589 short scrollBarCompensation = (gHaveScrollBar ? kScrollBarWidth : 0);
590 WindowPtr win = (**(ent->ctrl)).contrlOwner;
591
592 HLock((Handle)ent->ctrl);
593 sliderBounds = &(*(ent->ctrl))->contrlRect;
594 HUnlock((Handle)ent->ctrl);
595
596 SetRect(out, sliderBounds->left - kCtrlPad,
597 0, sliderBounds->right + kCtrlPad,
598 win->portRect.bottom - scrollBarCompensation);
599 }
600
601 void bar_draw(struct entity *ent)
602 {
603 ControlHandle ctrl = ent->ctrl;
604 char buf[128];
605 unsigned char* pBuf;
606 Rect sliderBounds = (*ctrl)->contrlRect;
607 Rect barBounds;
608 short width;
609 short val = GetControlValue(ctrl);
610
611 TextFont(1);
612 TextSize(10);
613
614 get_entity_bounds(ent, &barBounds);
615
616 EraseRect(&barBounds);
617 FrameRect(&barBounds);
618
619 snprintf(buf, 128, "%d%%",
620 (val * 100 + 127) / 255);
621
622 pBuf = c2pstr(buf);
623 width = StringWidth(pBuf);
624
625 MoveTo(barBounds.left + (kBarWidth - width)/2,
626 sliderBounds.bottom + 20);
627
628 DrawString(pBuf);
629
630 strcpy(buf, ent->state.name);
631 pBuf = c2pstr(buf);
632 width = StringWidth(pBuf);
633
634 MoveTo(barBounds.left + (kBarWidth - width) / 2,
635 sliderBounds.top - 10);
636
637 DrawString(pBuf);
638
639 SetRectRgn(ent->outerRgn, 0, 0, 0, 0);
640
641 OpenRgn();
642 FrameRect(&barBounds);
643 FrameRoundRect(&sliderBounds, 15, 15);
644 CloseRgn(ent->outerRgn);
645
646 if (ent->selected)
647 {
648 InvertRect(&barBounds);
649 }
650 }
651
652 void bars_draw()
653 {
654 list_t *node;
655 struct entity *ent;
656
657 list_foreach(&gEntities, node)
658 {
659 ent = container_of(node, struct entity, node);
660
661 bar_draw(ent);
662 }
663 }
664
665 void bars_update()
666 {
667 struct entity *ent;
668 list_t *node;
669 static uint32_t lastTickCount = 0;
670 WindowPeek win = (WindowPeek)gMainWindow;
671 short val;
672 bool changed = false;
673
674 if (lastTickCount + kBarUpdateRate > TickCount())
675 return;
676
677 list_foreach(&gEntities, node)
678 {
679 ent = container_of(node, struct entity, node);
680 val = GetControlValue(ent->ctrl);
681 ha_get_entity_state(ent->id, &ent->state);
682
683 if (ent->state.brightness != val)
684 {
685 SetControlValue(ent->ctrl, ent->state.brightness);
686 changed = true;
687 }
688 }
689
690 if (changed)
691 {
692 with_port(gMainWindow, {
693 InvalRect(&gMainWindow->portRect);
694 })
695 }
696
697 lastTickCount = TickCount();
698 }
699
700 void draw_background(WindowPtr win)
701 {
702 Rect drawRect;
703 short height = rect_height(&win->portRect);
704 short width = rect_width(&win->portRect);
705 short offset = kBarWidth * gNumBars;
706 if (offset > width)
707 return;
708
709 SetRect(&drawRect, offset, 0, width, height);
710
711 FillRect(&drawRect, &gBackPattern);
712 FrameRect(&drawRect);
713 }
714
715 struct entity *entity_for_control(ControlHandle hnd)
716 {
717 struct entity *ent;
718 list_t *node;
719
720 list_foreach(&gEntities, node)
721 {
722 ent = container_of(node, struct entity, node);
723 if (ent->ctrl == hnd)
724 return ent;
725 }
726
727 return NULL;
728 }
729
730 void event_update(WindowPtr win)
731 {
732 WindowPeek wPeek = (WindowPeek)win;
733
734 with_port(win, {
735 if (win == gMainWindow)
736 {
737 bars_draw();
738 draw_background(win);
739 UpdateControls(win, win->visRgn);
740 }
741 })
742 }
743
744 void update_entity_positions(short scrollValue)
745 {
746 struct entity *ent;
747 list_t *node;
748 Rect curPos;
749 short i = 0;
750
751 list_foreach(&gEntities, node)
752 {
753 ent = container_of(node, struct entity, node);
754 curPos = (**(ent->ctrl)).contrlRect;
755 MoveControl(ent->ctrl,
756 (i - scrollValue) * kBarWidth + kCtrlPad,
757 curPos.top);
758
759 i++;
760 }
761 }
762
763 void
764 control_mousedown(WindowPtr win, EventRecord* evt,
765 ControlHandle ctrl, short part)
766 {
767 short orig_val = GetControlValue(ctrl);
768 if (part = TrackControl(ctrl, evt->where, nil))
769 {
770 long ref = GetControlReference(ctrl);
771 switch (ref)
772 {
773 case CONTROL_SLIDER:
774 {
775 struct entity *ent = entity_for_control(ctrl);
776 short val = GetControlValue(ctrl);
777 InvalRect(&win->portRect);
778 ent->state.brightness = val;
779 ha_set_entity_state(ent->id, &ent->state);
780 break;
781 }
782 case CONTROL_SCROLLBAR:
783 {
784 short val = orig_val;
785 short max = GetControlMaximum(ctrl);
786
787 switch (part)
788 {
789 case inPageUp: // left gray
790 case inUpButton: // left
791 val = MAX(0, val - 1);
792 break;
793 case inPageDown: // right gray
794 case inDownButton: // right
795 val = MIN(max, val + 1);
796 break;
797 case inThumb:
798 // control manager calculates new value for us
799 val = GetControlValue(ctrl);
800 break;
801 }
802 SetControlValue(ctrl, val);
803
804 if (val != orig_val)
805 {
806 update_entity_positions(val);
807 InvalRect(&win->portRect);
808 }
809 break;
810 }
811 }
812 }
813 }
814
815 struct entity* find_entity_for_click(WindowPtr win, Point where)
816 {
817 struct entity *ent;
818 list_t *node;
819
820 if (win != gMainWindow)
821 return NULL;
822
823 list_foreach(&gEntities, node)
824 {
825 ent = container_of(node, struct entity, node);
826 if (PtInRgn(where, ent->outerRgn))
827 return ent;
828 }
829
830 return NULL;
831 }
832
833 void
834 event_mousedown(EventRecord* evt, WindowPtr win, short inPart)
835 {
836 WindowPtr frontWin = FrontWindow();
837 ControlHandle ctrl;
838 short inCtrlPart;
839 long menuChoice;
840
841 if (win_is_dialog(frontWin) && win != frontWin)
842 {
843 SysBeep(20);
844 return;
845 }
846
847 switch (inPart)
848 {
849 case inGoAway:
850 break;
851 case inMenuBar:
852 menuChoice = MenuSelect(evt->where);
853 if (menuChoice > 0)
854 menu_click(menuChoice);
855 break;
856 case inContent:
857 if (win_is_dialog(win))
858 {
859 struct dialog_info* dinfo = (void*)GetWRefCon(win);
860 dinfo->handle_mousedown(evt, win);
861 } else {
862 struct entity* ent;
863 GlobalToLocal(&evt->where);
864 inCtrlPart = FindControl(evt->where, win, &ctrl);
865 if (inCtrlPart)
866 {
867 control_mousedown(win, evt, ctrl, inCtrlPart);
868 }
869
870 if ((ent = find_entity_for_click(win, evt->where)))
871 {
872 Rect entityBounds;
873 ent->selected = !ent->selected;
874 get_entity_bounds(ent, &entityBounds);
875 InvalRect(&entityBounds);
876 }
877 }
878 break;
879 case inDrag:
880 DragWindow(win, evt->where, &qd.screenBits.bounds);
881 break;
882 case inSysWindow:
883 SystemClick(evt, win);
884 break;
885 default:
886 break;
887 }
888 }
889
890 void event_activate(bool activate, EventRecord* evt, WindowPtr win)
891 {
892 short junk;
893 if (win_is_dialog(win))
894 {
895 struct dialog_info* dinfo = (void*)GetWRefCon(win);
896 DialogSelect(evt, &(DialogPtr)win, &junk);
897 dinfo->handle_activate(activate, win);
898 }
899 }
900
901 void event_loop()
902 {
903 EventRecord event;
904 WindowPtr win;
905
906 short theChar;
907 short junk;
908 short inPart;
909
910 while (gRunning)
911 {
912 if (WaitNextEvent(everyEvent, &event, 60L, nil))
913 {
914 switch(event.what)
915 {
916 case mouseDown:
917 {
918 inPart = FindWindow(event.where, &win);
919 with_port(win, {
920 event_mousedown(&event, win, inPart);
921 })
922 break;
923 }
924 case updateEvt:
925 win = (WindowPtr)event.message;
926 if (win_is_dialog(win))
927 {
928 DialogSelect(&event, &(DialogPtr)win, &junk);
929 } else {
930 BeginUpdate(win);
931 event_update(win);
932 EndUpdate(win);
933 }
934 break;
935 case keyDown:
936 case autoKey:
937 theChar = event.message & charCodeMask;
938 if (event.modifiers & cmdKey)
939 menu_click(MenuKey(theChar));
940 break;
941 case activateEvt:
942 {
943 bool activate = event.modifiers & 1;
944 win = (WindowPtr)event.message;
945 event_activate(activate, &event, win);
946 break;
947 }
948 case osEvt:
949 if ((event.message >> 24) == suspendResumeMessage)
950 {
951 bool activate = event.message & 1;
952 win = FrontWindow();
953 event_activate(activate, &event, win);
954 }
955 break;
956 default:
957 break;
958 }
959 } else {
960 menu_update();
961 bars_update();
962 }
963 }
964 }