AmendHub

Download

cyberslak

/

lightsout

/

main.c

 

(View History)

cyberslak   Handle missing brightness key, update entity positions with new scrollbar value after bar_remove Latest amendment: 24 on 2025-03-17

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