this repo has no description
1/*
2 COMOSGLU.h
3
4 Copyright (C) 2009 Paul C. Pratt
5
6 You can redistribute this file and/or modify it under the terms
7 of version 2 of the GNU General Public License as published by
8 the Free Software Foundation. You should have received a copy
9 of the license along with this file; see the file COPYING.
10
11 This file is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 license for more details.
15*/
16
17/*
18 COMmon code for Operating System GLUe
19*/
20
21#if EnableMouseMotion && MayFullScreen
22#define EnableFSMouseMotion 1
23#else
24#define EnableFSMouseMotion 0
25#endif
26
27#if EnableMagnify || VarFullScreen
28#define EnableRecreateW 1
29#else
30#define EnableRecreateW 0
31#endif
32
33#if EnableRecreateW || EnableFSMouseMotion
34#define EnableMoveMouse 1
35#else
36#define EnableMoveMouse 0
37#endif
38
39GLOBALVAR ui3p ROM = nullpr;
40LOCALVAR blnr ROM_loaded = falseblnr;
41
42GLOBALVAR ui5b vSonyWritableMask = 0;
43GLOBALVAR ui5b vSonyInsertedMask = 0;
44
45#if IncludeSonyRawMode
46GLOBALVAR blnr vSonyRawMode = falseblnr;
47#endif
48
49#if IncludeSonyNew
50GLOBALVAR blnr vSonyNewDiskWanted = falseblnr;
51GLOBALVAR ui5b vSonyNewDiskSize;
52#endif
53
54#if IncludeSonyNameNew
55GLOBALVAR tPbuf vSonyNewDiskName = NotAPbuf;
56#endif
57
58GLOBALVAR ui5b CurMacDateInSeconds = 0;
59#if AutoLocation
60GLOBALVAR ui5b CurMacLatitude = 0;
61GLOBALVAR ui5b CurMacLongitude = 0;
62#endif
63#if AutoTimeZone
64GLOBALVAR ui5b CurMacDelta = 0;
65#endif
66
67#if 0 != vMacScreenDepth
68GLOBALVAR blnr UseColorMode = falseblnr;
69GLOBALVAR blnr ColorModeWorks = falseblnr;
70#endif
71
72#if 0 != vMacScreenDepth
73GLOBALVAR blnr ColorMappingChanged = falseblnr;
74#endif
75
76#if (0 != vMacScreenDepth) && (vMacScreenDepth < 4)
77GLOBALVAR ui4r CLUT_reds[CLUT_size];
78GLOBALVAR ui4r CLUT_greens[CLUT_size];
79GLOBALVAR ui4r CLUT_blues[CLUT_size];
80#endif
81
82LOCALVAR blnr RequestMacOff = falseblnr;
83
84GLOBALVAR blnr ForceMacOff = falseblnr;
85
86GLOBALVAR blnr WantMacInterrupt = falseblnr;
87
88GLOBALVAR blnr WantMacReset = falseblnr;
89
90GLOBALVAR ui3b SpeedValue = WantInitSpeedValue;
91
92#if EnableAutoSlow
93GLOBALVAR blnr WantNotAutoSlow = (WantInitNotAutoSlow != 0);
94#endif
95
96GLOBALVAR ui4b CurMouseV = 0;
97GLOBALVAR ui4b CurMouseH = 0;
98
99#if EnableFSMouseMotion
100LOCALVAR blnr HaveMouseMotion = falseblnr;
101#endif
102
103#if EnableAutoSlow
104GLOBALVAR ui5r QuietTime = 0;
105GLOBALVAR ui5r QuietSubTicks = 0;
106#endif
107
108#if EmLocalTalk
109
110GLOBALVAR ui3b LT_NodeHint = 0;
111
112#if LT_MayHaveEcho
113GLOBALVAR blnr CertainlyNotMyPacket = falseblnr;
114#endif
115
116GLOBALVAR ui3p LT_TxBuffer = NULL;
117
118/* Transmit state */
119GLOBALVAR ui4r LT_TxBuffSz = 0;
120
121/* Receive state */
122GLOBALVAR ui3p LT_RxBuffer = NULL;
123 /* When data pending, this is used */
124GLOBALVAR ui5r LT_RxBuffSz = 0;
125 /* When data pending, this is used */
126
127#endif
128
129#ifndef GrabKeysFullScreen
130#define GrabKeysFullScreen 1
131#endif
132
133#ifndef GrabKeysMaxFullScreen
134#define GrabKeysMaxFullScreen 0
135#endif
136
137#if IncludePbufs
138LOCALVAR ui5b PbufAllocatedMask;
139LOCALVAR ui5b PbufSize[NumPbufs];
140#endif
141
142#if IncludePbufs
143#define PbufIsAllocated(i) ((PbufAllocatedMask & ((ui5b)1 << (i))) != 0)
144#endif
145
146#if IncludePbufs
147LOCALFUNC blnr FirstFreePbuf(tPbuf *r)
148{
149 tPbuf i;
150
151 for (i = 0; i < NumPbufs; ++i) {
152 if (! PbufIsAllocated(i)) {
153 *r = i;
154 return trueblnr;
155 }
156 }
157 return falseblnr;
158}
159#endif
160
161#if IncludePbufs
162LOCALPROC PbufNewNotify(tPbuf Pbuf_No, ui5b count)
163{
164 PbufSize[Pbuf_No] = count;
165 PbufAllocatedMask |= ((ui5b)1 << Pbuf_No);
166}
167#endif
168
169#if IncludePbufs
170LOCALPROC PbufDisposeNotify(tPbuf Pbuf_No)
171{
172 PbufAllocatedMask &= ~ ((ui5b)1 << Pbuf_No);
173}
174#endif
175
176#if IncludePbufs
177GLOBALOSGLUFUNC tMacErr CheckPbuf(tPbuf Pbuf_No)
178{
179 tMacErr result;
180
181 if (Pbuf_No >= NumPbufs) {
182 result = mnvm_nsDrvErr;
183 } else if (! PbufIsAllocated(Pbuf_No)) {
184 result = mnvm_offLinErr;
185 } else {
186 result = mnvm_noErr;
187 }
188
189 return result;
190}
191#endif
192
193#if IncludePbufs
194GLOBALOSGLUFUNC tMacErr PbufGetSize(tPbuf Pbuf_No, ui5r *Count)
195{
196 tMacErr result = CheckPbuf(Pbuf_No);
197
198 if (mnvm_noErr == result) {
199 *Count = PbufSize[Pbuf_No];
200 }
201
202 return result;
203}
204#endif
205
206LOCALFUNC blnr FirstFreeDisk(tDrive *Drive_No)
207{
208 tDrive i;
209
210 for (i = 0; i < NumDrives; ++i) {
211 if (! vSonyIsInserted(i)) {
212 if (nullpr != Drive_No) {
213 *Drive_No = i;
214 }
215 return trueblnr;
216 }
217 }
218 return falseblnr;
219}
220
221GLOBALOSGLUFUNC blnr AnyDiskInserted(void)
222{
223#if 0
224 tDrive i;
225
226 for (i = 0; i < NumDrives; ++i) {
227 if (vSonyIsInserted(i)) {
228 return trueblnr;
229 }
230 }
231 return falseblnr;
232#endif
233 return 0 != vSonyInsertedMask;
234}
235
236GLOBALOSGLUPROC DiskRevokeWritable(tDrive Drive_No)
237{
238 vSonyWritableMask &= ~ ((ui5b)1 << Drive_No);
239}
240
241LOCALPROC DiskInsertNotify(tDrive Drive_No, blnr locked)
242{
243 vSonyInsertedMask |= ((ui5b)1 << Drive_No);
244 if (! locked) {
245 vSonyWritableMask |= ((ui5b)1 << Drive_No);
246 }
247
248 QuietEnds();
249}
250
251LOCALPROC DiskEjectedNotify(tDrive Drive_No)
252{
253 vSonyWritableMask &= ~ ((ui5b)1 << Drive_No);
254 vSonyInsertedMask &= ~ ((ui5b)1 << Drive_No);
255}
256
257/*
258 block type - for operating on multiple ui3b elements
259 at a time.
260*/
261
262#if LittleEndianUnaligned || BigEndianUnaligned
263
264#define uibb ui5b
265#define uibr ui5r
266#define ln2uiblockn 2
267
268#if 0
269#define uibb long long
270#define uibr long long
271#define ln2uiblockn 3
272#endif
273
274#else
275
276#define uibb ui3b
277#define uibr ui3r
278#define ln2uiblockn 0
279
280#endif
281
282#define uiblockn (1 << ln2uiblockn)
283#define ln2uiblockbitsn (3 + ln2uiblockn)
284#define uiblockbitsn (8 * uiblockn)
285
286LOCALFUNC blnr FindFirstChangeInLVecs(uibb *ptr1, uibb *ptr2,
287 uimr L, uimr *j)
288{
289/*
290 find index of first difference
291*/
292 uibb *p1 = ptr1;
293 uibb *p2 = ptr2;
294 uimr i;
295
296 for (i = L; i != 0; --i) {
297 if (*p1++ != *p2++) {
298 --p1;
299 *j = p1 - ptr1;
300 return trueblnr;
301 }
302 }
303 return falseblnr;
304}
305
306LOCALPROC FindLastChangeInLVecs(uibb *ptr1, uibb *ptr2,
307 uimr L, uimr *j)
308{
309/*
310 find index of last difference, assuming there is one
311*/
312 uibb *p1 = ptr1 + L;
313 uibb *p2 = ptr2 + L;
314
315 while (*--p1 == *--p2) {
316 }
317 *j = p1 - ptr1;
318}
319
320LOCALPROC FindLeftRightChangeInLMat(uibb *ptr1, uibb *ptr2,
321 uimr width, uimr top, uimr bottom,
322 uimr *LeftMin0, uibr *LeftMask0,
323 uimr *RightMax0, uibr *RightMask0)
324{
325 uimr i;
326 uimr j;
327 uibb *p1;
328 uibb *p2;
329 uibr x;
330 ui5r offset = top * width;
331 uibb *p10 = (uibb *)ptr1 + offset;
332 uibb *p20 = (uibb *)ptr2 + offset;
333 uimr LeftMin = *LeftMin0;
334 uimr RightMax = *RightMax0;
335 uibr LeftMask = 0;
336 uibr RightMask = 0;
337 for (i = top; i < bottom; ++i) {
338 p1 = p10;
339 p2 = p20;
340 for (j = 0; j < LeftMin; ++j) {
341 x = *p1++ ^ *p2++;
342 if (0 != x) {
343 LeftMin = j;
344 LeftMask = x;
345 goto Label_3;
346 }
347 }
348 LeftMask |= (*p1 ^ *p2);
349Label_3:
350 p1 = p10 + RightMax;
351 p2 = p20 + RightMax;
352 RightMask |= (*p1++ ^ *p2++);
353 for (j = RightMax + 1; j < width; ++j) {
354 x = *p1++ ^ *p2++;
355 if (0 != x) {
356 RightMax = j;
357 RightMask = x;
358 }
359 }
360
361 p10 += width;
362 p20 += width;
363 }
364 *LeftMin0 = LeftMin;
365 *RightMax0 = RightMax;
366 *LeftMask0 = LeftMask;
367 *RightMask0 = RightMask;
368}
369
370LOCALVAR ui3p screencomparebuff = nullpr;
371
372LOCALVAR uimr NextDrawRow = 0;
373
374
375#if BigEndianUnaligned
376
377#define FlipCheckMonoBits (uiblockbitsn - 1)
378
379#else
380
381#define FlipCheckMonoBits 7
382
383#endif
384
385#define FlipCheckBits (FlipCheckMonoBits >> vMacScreenDepth)
386
387#ifndef WantColorTransValid
388#define WantColorTransValid 0
389#endif
390
391#if WantColorTransValid
392LOCALVAR blnr ColorTransValid = falseblnr;
393#endif
394
395LOCALFUNC blnr ScreenFindChanges(ui3p screencurrentbuff,
396 si3b TimeAdjust, si4b *top, si4b *left, si4b *bottom, si4b *right)
397{
398 uimr j0;
399 uimr j1;
400 uimr j0h;
401 uimr j1h;
402 uimr j0v;
403 uimr j1v;
404 uimr copysize;
405 uimr copyoffset;
406 uimr copyrows;
407 uimr LimitDrawRow;
408 uimr MaxRowsDrawnPerTick;
409 uimr LeftMin;
410 uimr RightMax;
411 uibr LeftMask;
412 uibr RightMask;
413 int j;
414
415 if (TimeAdjust < 4) {
416 MaxRowsDrawnPerTick = vMacScreenHeight;
417 } else if (TimeAdjust < 6) {
418 MaxRowsDrawnPerTick = vMacScreenHeight / 2;
419 } else {
420 MaxRowsDrawnPerTick = vMacScreenHeight / 4;
421 }
422
423#if 0 != vMacScreenDepth
424 if (UseColorMode) {
425 if (ColorMappingChanged) {
426 ColorMappingChanged = falseblnr;
427 j0h = 0;
428 j1h = vMacScreenWidth;
429 j0v = 0;
430 j1v = vMacScreenHeight;
431#if WantColorTransValid
432 ColorTransValid = falseblnr;
433#endif
434 } else {
435 if (! FindFirstChangeInLVecs(
436 (uibb *)screencurrentbuff
437 + NextDrawRow * (vMacScreenBitWidth / uiblockbitsn),
438 (uibb *)screencomparebuff
439 + NextDrawRow * (vMacScreenBitWidth / uiblockbitsn),
440 ((uimr)(vMacScreenHeight - NextDrawRow)
441 * (uimr)vMacScreenBitWidth) / uiblockbitsn,
442 &j0))
443 {
444 NextDrawRow = 0;
445 return falseblnr;
446 }
447 j0v = j0 / (vMacScreenBitWidth / uiblockbitsn);
448 j0h = j0 - j0v * (vMacScreenBitWidth / uiblockbitsn);
449 j0v += NextDrawRow;
450 LimitDrawRow = j0v + MaxRowsDrawnPerTick;
451 if (LimitDrawRow >= vMacScreenHeight) {
452 LimitDrawRow = vMacScreenHeight;
453 NextDrawRow = 0;
454 } else {
455 NextDrawRow = LimitDrawRow;
456 }
457 FindLastChangeInLVecs((uibb *)screencurrentbuff,
458 (uibb *)screencomparebuff,
459 ((uimr)LimitDrawRow
460 * (uimr)vMacScreenBitWidth) / uiblockbitsn,
461 &j1);
462 j1v = j1 / (vMacScreenBitWidth / uiblockbitsn);
463 j1h = j1 - j1v * (vMacScreenBitWidth / uiblockbitsn);
464 j1v++;
465
466 if (j0h < j1h) {
467 LeftMin = j0h;
468 RightMax = j1h;
469 } else {
470 LeftMin = j1h;
471 RightMax = j0h;
472 }
473
474 FindLeftRightChangeInLMat((uibb *)screencurrentbuff,
475 (uibb *)screencomparebuff,
476 (vMacScreenBitWidth / uiblockbitsn),
477 j0v, j1v, &LeftMin, &LeftMask, &RightMax, &RightMask);
478
479#if vMacScreenDepth > ln2uiblockbitsn
480 j0h = (LeftMin >> (vMacScreenDepth - ln2uiblockbitsn));
481#elif ln2uiblockbitsn > vMacScreenDepth
482 for (j = 0; j < (1 << (ln2uiblockbitsn - vMacScreenDepth));
483 ++j)
484 {
485 if (0 != (LeftMask
486 & (((((uibr)1) << (1 << vMacScreenDepth)) - 1)
487 << ((j ^ FlipCheckBits) << vMacScreenDepth))))
488 {
489 goto Label_1c;
490 }
491 }
492Label_1c:
493 j0h = (LeftMin << (ln2uiblockbitsn - vMacScreenDepth)) + j;
494#else
495 j0h = LeftMin;
496#endif
497
498#if vMacScreenDepth > ln2uiblockbitsn
499 j1h = (RightMax >> (vMacScreenDepth - ln2uiblockbitsn)) + 1;
500#elif ln2uiblockbitsn > vMacScreenDepth
501 for (j = (uiblockbitsn >> vMacScreenDepth); --j >= 0; ) {
502 if (0 != (RightMask
503 & (((((uibr)1) << (1 << vMacScreenDepth)) - 1)
504 << ((j ^ FlipCheckBits) << vMacScreenDepth))))
505 {
506 goto Label_2c;
507 }
508 }
509Label_2c:
510 j1h = (RightMax << (ln2uiblockbitsn - vMacScreenDepth))
511 + j + 1;
512#else
513 j1h = RightMax + 1;
514#endif
515 }
516
517 copyrows = j1v - j0v;
518 copyoffset = j0v * vMacScreenByteWidth;
519 copysize = copyrows * vMacScreenByteWidth;
520 } else
521#endif
522 {
523#if 0 != vMacScreenDepth
524 if (ColorMappingChanged) {
525 ColorMappingChanged = falseblnr;
526 j0h = 0;
527 j1h = vMacScreenWidth;
528 j0v = 0;
529 j1v = vMacScreenHeight;
530#if WantColorTransValid
531 ColorTransValid = falseblnr;
532#endif
533 } else
534#endif
535 {
536 if (! FindFirstChangeInLVecs(
537 (uibb *)screencurrentbuff
538 + NextDrawRow * (vMacScreenWidth / uiblockbitsn),
539 (uibb *)screencomparebuff
540 + NextDrawRow * (vMacScreenWidth / uiblockbitsn),
541 ((uimr)(vMacScreenHeight - NextDrawRow)
542 * (uimr)vMacScreenWidth) / uiblockbitsn,
543 &j0))
544 {
545 NextDrawRow = 0;
546 return falseblnr;
547 }
548 j0v = j0 / (vMacScreenWidth / uiblockbitsn);
549 j0h = j0 - j0v * (vMacScreenWidth / uiblockbitsn);
550 j0v += NextDrawRow;
551 LimitDrawRow = j0v + MaxRowsDrawnPerTick;
552 if (LimitDrawRow >= vMacScreenHeight) {
553 LimitDrawRow = vMacScreenHeight;
554 NextDrawRow = 0;
555 } else {
556 NextDrawRow = LimitDrawRow;
557 }
558 FindLastChangeInLVecs((uibb *)screencurrentbuff,
559 (uibb *)screencomparebuff,
560 ((uimr)LimitDrawRow
561 * (uimr)vMacScreenWidth) / uiblockbitsn,
562 &j1);
563 j1v = j1 / (vMacScreenWidth / uiblockbitsn);
564 j1h = j1 - j1v * (vMacScreenWidth / uiblockbitsn);
565 j1v++;
566
567 if (j0h < j1h) {
568 LeftMin = j0h;
569 RightMax = j1h;
570 } else {
571 LeftMin = j1h;
572 RightMax = j0h;
573 }
574
575 FindLeftRightChangeInLMat((uibb *)screencurrentbuff,
576 (uibb *)screencomparebuff,
577 (vMacScreenWidth / uiblockbitsn),
578 j0v, j1v, &LeftMin, &LeftMask, &RightMax, &RightMask);
579
580 for (j = 0; j < uiblockbitsn; ++j) {
581 if (0 != (LeftMask
582 & (((uibr)1) << (j ^ FlipCheckMonoBits))))
583 {
584 goto Label_1;
585 }
586 }
587Label_1:
588 j0h = LeftMin * uiblockbitsn + j;
589
590 for (j = uiblockbitsn; --j >= 0; ) {
591 if (0 != (RightMask
592 & (((uibr)1) << (j ^ FlipCheckMonoBits))))
593 {
594 goto Label_2;
595 }
596 }
597Label_2:
598 j1h = RightMax * uiblockbitsn + j + 1;
599 }
600
601 copyrows = j1v - j0v;
602 copyoffset = j0v * vMacScreenMonoByteWidth;
603 copysize = copyrows * vMacScreenMonoByteWidth;
604 }
605
606 MyMoveBytes((anyp)screencurrentbuff + copyoffset,
607 (anyp)screencomparebuff + copyoffset,
608 copysize);
609
610 *top = j0v;
611 *left = j0h;
612 *bottom = j1v;
613 *right = j1h;
614
615 return trueblnr;
616}
617
618GLOBALVAR blnr EmVideoDisable = falseblnr;
619GLOBALVAR si3b EmLagTime = 0;
620
621GLOBALVAR ui5b OnTrueTime = 0;
622 /*
623 The time slice we are currently dealing
624 with, in the same units as TrueEmulatedTime.
625 */
626
627LOCALVAR si4b ScreenChangedTop;
628LOCALVAR si4b ScreenChangedLeft;
629LOCALVAR si4b ScreenChangedBottom;
630LOCALVAR si4b ScreenChangedRight;
631
632LOCALPROC ScreenClearChanges(void)
633{
634 ScreenChangedTop = vMacScreenHeight;
635 ScreenChangedBottom = 0;
636 ScreenChangedLeft = vMacScreenWidth;
637 ScreenChangedRight = 0;
638}
639
640LOCALPROC ScreenChangedAll(void)
641{
642 ScreenChangedTop = 0;
643 ScreenChangedBottom = vMacScreenHeight;
644 ScreenChangedLeft = 0;
645 ScreenChangedRight = vMacScreenWidth;
646}
647
648#if EnableAutoSlow
649LOCALVAR si4b ScreenChangedQuietTop = vMacScreenHeight;
650LOCALVAR si4b ScreenChangedQuietLeft = vMacScreenWidth;
651LOCALVAR si4b ScreenChangedQuietBottom = 0;
652LOCALVAR si4b ScreenChangedQuietRight = 0;
653#endif
654
655GLOBALOSGLUPROC Screen_OutputFrame(ui3p screencurrentbuff)
656{
657 si4b top;
658 si4b left;
659 si4b bottom;
660 si4b right;
661
662 if (! EmVideoDisable) {
663 if (ScreenFindChanges(screencurrentbuff, EmLagTime,
664 &top, &left, &bottom, &right))
665 {
666 if (top < ScreenChangedTop) {
667 ScreenChangedTop = top;
668 }
669 if (bottom > ScreenChangedBottom) {
670 ScreenChangedBottom = bottom;
671 }
672 if (left < ScreenChangedLeft) {
673 ScreenChangedLeft = left;
674 }
675 if (right > ScreenChangedRight) {
676 ScreenChangedRight = right;
677 }
678
679#if EnableAutoSlow
680 if (top < ScreenChangedQuietTop) {
681 ScreenChangedQuietTop = top;
682 }
683 if (bottom > ScreenChangedQuietBottom) {
684 ScreenChangedQuietBottom = bottom;
685 }
686 if (left < ScreenChangedQuietLeft) {
687 ScreenChangedQuietLeft = left;
688 }
689 if (right > ScreenChangedQuietRight) {
690 ScreenChangedQuietRight = right;
691 }
692
693 if (((ScreenChangedQuietRight - ScreenChangedQuietLeft) > 1)
694 || ((ScreenChangedQuietBottom
695 - ScreenChangedQuietTop) > 32))
696 {
697 ScreenChangedQuietTop = vMacScreenHeight;
698 ScreenChangedQuietLeft = vMacScreenWidth;
699 ScreenChangedQuietBottom = 0;
700 ScreenChangedQuietRight = 0;
701
702 QuietEnds();
703 }
704#endif
705 }
706 }
707}
708
709#if MayFullScreen
710LOCALVAR ui4r ViewHSize;
711LOCALVAR ui4r ViewVSize;
712LOCALVAR ui4r ViewHStart = 0;
713LOCALVAR ui4r ViewVStart = 0;
714#if EnableFSMouseMotion
715LOCALVAR si4b SavedMouseH;
716LOCALVAR si4b SavedMouseV;
717#endif
718#endif
719
720#ifndef WantAutoScrollBorder
721#define WantAutoScrollBorder 0
722#endif
723
724#if EnableFSMouseMotion
725LOCALPROC AutoScrollScreen(void)
726{
727 si4b Shift;
728 si4b Limit;
729
730 /*
731 Scroll in multiples of two pixels, so as to
732 work better with the common gray pattern.
733 ViewHSize and ViewVSize are constrained
734 to a multiple of two.
735
736 Mac OS (some versions at least) constrains
737 the mouse position to be less than the screen
738 height and width, not allowing equal to it.
739 Can still scroll to see last pixel because
740 scroll in multiples of two pixels.
741 */
742
743 if (vMacScreenWidth != ViewHSize) {
744 Shift = 0;
745 Limit = ViewHStart
746#if WantAutoScrollBorder
747 + (ViewHSize / 16)
748#endif
749 ;
750 if (CurMouseH < Limit) {
751 Shift = (Limit - CurMouseH + 1) & (~ 1);
752 Limit = ViewHStart;
753 if (Shift >= Limit) {
754 Shift = Limit;
755 }
756 Shift = - Shift;
757 } else {
758 Limit = ViewHStart + ViewHSize
759#if WantAutoScrollBorder
760 - (ViewHSize / 16)
761#endif
762 ;
763 if (CurMouseH > Limit) {
764 Shift = (CurMouseH - Limit + 1) & (~ 1);
765 Limit = vMacScreenWidth - ViewHSize - ViewHStart;
766 if (Shift >= Limit) {
767 Shift = Limit;
768 }
769 }
770 }
771
772 if (Shift != 0) {
773 ViewHStart += Shift;
774 SavedMouseH += Shift;
775 ScreenChangedAll();
776 }
777 }
778
779 if (vMacScreenHeight != ViewVSize) {
780 Shift = 0;
781 Limit = ViewVStart
782#if WantAutoScrollBorder
783 + (ViewVSize / 16)
784#endif
785 ;
786 if (CurMouseV < Limit) {
787 Shift = (Limit - CurMouseV + 1) & (~ 1);
788 Limit = ViewVStart;
789 if (Shift >= Limit) {
790 Shift = Limit;
791 }
792 Shift = - Shift;
793 } else {
794 Limit = ViewVStart + ViewVSize
795#if WantAutoScrollBorder
796 - (ViewVSize / 16)
797#endif
798 ;
799 if (CurMouseV > Limit) {
800 Shift = (CurMouseV - Limit + 1) & (~ 1);
801 Limit = vMacScreenHeight - ViewVSize - ViewVStart;
802 if (Shift >= Limit) {
803 Shift = Limit;
804 }
805 }
806 }
807
808 if (Shift != 0) {
809 ViewVStart += Shift;
810 SavedMouseV += Shift;
811 ScreenChangedAll();
812 }
813 }
814}
815#endif
816
817LOCALPROC SetLongs(ui5b *p, long n)
818{
819 long i;
820
821 for (i = n; --i >= 0; ) {
822 *p++ = (ui5b) -1;
823 }
824}
825
826LOCALVAR uimr ReserveAllocOffset;
827LOCALVAR ui3p ReserveAllocBigBlock = nullpr;
828
829#define PowOf2(p) ((uimr)1 << (p))
830#define Pow2Mask(p) (PowOf2(p) - 1)
831#define ModPow2(i, p) ((i) & Pow2Mask(p))
832#define FloorDivPow2(i, p) ((i) >> (p))
833#define FloorPow2Mult(i, p) ((i) & (~ Pow2Mask(p)))
834#define CeilPow2Mult(i, p) FloorPow2Mult((i) + Pow2Mask(p), (p))
835 /* warning - CeilPow2Mult evaluates p twice */
836
837GLOBALOSGLUPROC ReserveAllocOneBlock(ui3p *p, uimr n,
838 ui3r align, blnr FillOnes)
839{
840 ReserveAllocOffset = CeilPow2Mult(ReserveAllocOffset, align);
841 if (nullpr == ReserveAllocBigBlock) {
842 *p = nullpr;
843 } else {
844 *p = ReserveAllocBigBlock + ReserveAllocOffset;
845 if (FillOnes) {
846 SetLongs((ui5b *)*p, n / 4);
847 }
848 }
849 ReserveAllocOffset += n;
850}
851
852/* --- sending debugging info to file --- */
853
854#if dbglog_HAVE
855
856#ifndef dbglog_buflnsz
857
858#define dbglog_ReserveAlloc()
859#define dbglog_close dbglog_close0
860#define dbglog_open dbglog_open0
861#define dbglog_write dbglog_write0
862
863#else
864
865#define dbglog_bufsz PowOf2(dbglog_buflnsz)
866LOCALVAR uimr dbglog_bufpos = 0;
867
868LOCALVAR char *dbglog_bufp = nullpr;
869
870LOCALPROC dbglog_ReserveAlloc(void)
871{
872 ReserveAllocOneBlock((ui3p *)&dbglog_bufp, dbglog_bufsz,
873 5, falseblnr);
874}
875
876#define dbglog_open dbglog_open0
877
878LOCALPROC dbglog_close(void)
879{
880 uimr n = ModPow2(dbglog_bufpos, dbglog_buflnsz);
881 if (n != 0) {
882 dbglog_write0(dbglog_bufp, n);
883 }
884
885 dbglog_close0();
886}
887
888LOCALPROC dbglog_write(char *p, uimr L)
889{
890 uimr r;
891 uimr bufposmod;
892 uimr curbufdiv;
893 uimr newbufpos = dbglog_bufpos + L;
894 uimr newbufdiv = FloorDivPow2(newbufpos, dbglog_buflnsz);
895
896label_retry:
897 curbufdiv = FloorDivPow2(dbglog_bufpos, dbglog_buflnsz);
898 bufposmod = ModPow2(dbglog_bufpos, dbglog_buflnsz);
899 if (newbufdiv != curbufdiv) {
900 r = dbglog_bufsz - bufposmod;
901 MyMoveBytes((anyp)p, (anyp)(dbglog_bufp + bufposmod), r);
902 dbglog_write0(dbglog_bufp, dbglog_bufsz);
903 L -= r;
904 p += r;
905 dbglog_bufpos += r;
906 goto label_retry;
907 }
908 MyMoveBytes((anyp)p, (anyp)dbglog_bufp + bufposmod, L);
909 dbglog_bufpos = newbufpos;
910}
911
912#endif /* dbglog_buflnsz defined */
913
914LOCALFUNC uimr CStrLength(char *s)
915{
916 char *p = s;
917
918 while (*p++ != 0) {
919 }
920 return p - s - 1;
921}
922
923GLOBALOSGLUPROC dbglog_writeCStr(char *s)
924{
925 /* fprintf(DumpFile, "%s", s); */
926 dbglog_write(s, CStrLength(s));
927}
928
929GLOBALOSGLUPROC dbglog_writeReturn(void)
930{
931 dbglog_writeCStr("\n");
932 /* fprintf(DumpFile, "\n"); */
933}
934
935GLOBALOSGLUPROC dbglog_writeHex(uimr x)
936{
937 ui3r v;
938 char s[16];
939 char *p = s + 16;
940 uimr n = 0;
941
942 do {
943 v = x & 0x0F;
944 if (v < 10) {
945 *--p = '0' + v;
946 } else {
947 *--p = 'A' + v - 10;
948 }
949 x >>= 4;
950 ++n;
951 } while (x != 0);
952
953 dbglog_write(p, n);
954 /* fprintf(DumpFile, "%d", (int)x); */
955}
956
957GLOBALOSGLUPROC dbglog_writeNum(uimr x)
958{
959 uimr newx;
960 char s[16];
961 char *p = s + 16;
962 uimr n = 0;
963
964 do {
965 newx = x / (uimr)10;
966 *--p = '0' + (x - newx * 10);
967 x = newx;
968 ++n;
969 } while (x != 0);
970
971 dbglog_write(p, n);
972 /* fprintf(DumpFile, "%d", (int)x); */
973}
974
975GLOBALOSGLUPROC dbglog_writeMacChar(ui3r x)
976{
977 char s;
978
979 if ((x > 32) && (x < 127)) {
980 s = x;
981 } else {
982 s = '?';
983 }
984
985 dbglog_write(&s, 1);
986}
987
988LOCALPROC dbglog_writeSpace(void)
989{
990 dbglog_writeCStr(" ");
991}
992
993GLOBALOSGLUPROC dbglog_writeln(char *s)
994{
995 dbglog_writeCStr(s);
996 dbglog_writeReturn();
997}
998
999GLOBALOSGLUPROC dbglog_writelnHex(char *s, uimr x)
1000{
1001 dbglog_writeCStr(s);
1002 dbglog_writeSpace();
1003 dbglog_writeHex(x);
1004 dbglog_writeReturn();
1005}
1006
1007GLOBALOSGLUPROC dbglog_writelnNum(char *s, simr v)
1008{
1009 dbglog_writeCStr(s);
1010 dbglog_writeSpace();
1011 dbglog_writeNum(v);
1012 dbglog_writeReturn();
1013}
1014
1015#endif /* dbglog_HAVE */
1016
1017
1018/* my event queue */
1019
1020#define MyEvtQLg2Sz 4
1021#define MyEvtQSz (1 << MyEvtQLg2Sz)
1022#define MyEvtQIMask (MyEvtQSz - 1)
1023
1024LOCALVAR MyEvtQEl MyEvtQA[MyEvtQSz];
1025LOCALVAR ui4r MyEvtQIn = 0;
1026LOCALVAR ui4r MyEvtQOut = 0;
1027
1028GLOBALOSGLUFUNC MyEvtQEl * MyEvtQOutP(void)
1029{
1030 MyEvtQEl *p = nullpr;
1031 if (MyEvtQIn != MyEvtQOut) {
1032 p = &MyEvtQA[MyEvtQOut & MyEvtQIMask];
1033 }
1034 return p;
1035}
1036
1037GLOBALOSGLUPROC MyEvtQOutDone(void)
1038{
1039 ++MyEvtQOut;
1040}
1041
1042LOCALVAR blnr MyEvtQNeedRecover = falseblnr;
1043 /* events lost because of full queue */
1044
1045LOCALFUNC MyEvtQEl * MyEvtQElPreviousIn(void)
1046{
1047 MyEvtQEl *p = NULL;
1048 if (MyEvtQIn - MyEvtQOut != 0) {
1049 p = &MyEvtQA[(MyEvtQIn - 1) & MyEvtQIMask];
1050 }
1051
1052 return p;
1053}
1054
1055LOCALFUNC MyEvtQEl * MyEvtQElAlloc(void)
1056{
1057 MyEvtQEl *p = NULL;
1058 if (MyEvtQIn - MyEvtQOut >= MyEvtQSz) {
1059 MyEvtQNeedRecover = trueblnr;
1060 } else {
1061 p = &MyEvtQA[MyEvtQIn & MyEvtQIMask];
1062
1063 ++MyEvtQIn;
1064 }
1065
1066 return p;
1067}
1068
1069LOCALVAR ui5b theKeys[4];
1070
1071LOCALPROC Keyboard_UpdateKeyMap(ui3r key, blnr down)
1072{
1073 ui3r k = key & 127; /* just for safety */
1074 ui3r bit = 1 << (k & 7);
1075 ui3b *kp = (ui3b *)theKeys;
1076 ui3b *kpi = &kp[k / 8];
1077 blnr CurDown = ((*kpi & bit) != 0);
1078 if (CurDown != down) {
1079 MyEvtQEl *p = MyEvtQElAlloc();
1080 if (NULL != p) {
1081 p->kind = MyEvtQElKindKey;
1082 p->u.press.key = k;
1083 p->u.press.down = down;
1084
1085 if (down) {
1086 *kpi |= bit;
1087 } else {
1088 *kpi &= ~ bit;
1089 }
1090 }
1091
1092 QuietEnds();
1093 }
1094}
1095
1096LOCALVAR blnr MyMouseButtonState = falseblnr;
1097
1098LOCALPROC MyMouseButtonSet(blnr down)
1099{
1100 if (MyMouseButtonState != down) {
1101 MyEvtQEl *p = MyEvtQElAlloc();
1102 if (NULL != p) {
1103 p->kind = MyEvtQElKindMouseButton;
1104 p->u.press.down = down;
1105
1106 MyMouseButtonState = down;
1107 }
1108
1109 QuietEnds();
1110 }
1111}
1112
1113#if EnableFSMouseMotion
1114LOCALPROC MyMousePositionSetDelta(ui4r dh, ui4r dv)
1115{
1116 if ((dh != 0) || (dv != 0)) {
1117 MyEvtQEl *p = MyEvtQElPreviousIn();
1118 if ((NULL != p) && (MyEvtQElKindMouseDelta == p->kind)) {
1119 p->u.pos.h += dh;
1120 p->u.pos.v += dv;
1121 } else {
1122 p = MyEvtQElAlloc();
1123 if (NULL != p) {
1124 p->kind = MyEvtQElKindMouseDelta;
1125 p->u.pos.h = dh;
1126 p->u.pos.v = dv;
1127 }
1128 }
1129
1130 QuietEnds();
1131 }
1132}
1133#endif
1134
1135LOCALVAR ui4b MyMousePosCurV = 0;
1136LOCALVAR ui4b MyMousePosCurH = 0;
1137
1138LOCALPROC MyMousePositionSet(ui4r h, ui4r v)
1139{
1140 if ((h != MyMousePosCurH) || (v != MyMousePosCurV)) {
1141 MyEvtQEl *p = MyEvtQElPreviousIn();
1142 if ((NULL == p) || (MyEvtQElKindMousePos != p->kind)) {
1143 p = MyEvtQElAlloc();
1144 }
1145 if (NULL != p) {
1146 p->kind = MyEvtQElKindMousePos;
1147 p->u.pos.h = h;
1148 p->u.pos.v = v;
1149
1150 MyMousePosCurH = h;
1151 MyMousePosCurV = v;
1152 }
1153
1154 QuietEnds();
1155 }
1156}
1157
1158#if 0
1159#define Keyboard_TestKeyMap(key) \
1160 ((((ui3b *)theKeys)[(key) / 8] & (1 << ((key) & 7))) != 0)
1161#endif
1162
1163LOCALPROC InitKeyCodes(void)
1164{
1165 theKeys[0] = 0;
1166 theKeys[1] = 0;
1167 theKeys[2] = 0;
1168 theKeys[3] = 0;
1169}
1170
1171#define kKeepMaskControl (1 << 0)
1172#define kKeepMaskCapsLock (1 << 1)
1173#define kKeepMaskCommand (1 << 2)
1174#define kKeepMaskOption (1 << 3)
1175#define kKeepMaskShift (1 << 4)
1176
1177LOCALPROC DisconnectKeyCodes(ui5b KeepMask)
1178{
1179 /*
1180 Called when may miss key ups,
1181 so act is if all pressed keys have been released,
1182 except maybe for control, caps lock, command,
1183 option and shift.
1184 */
1185
1186 int j;
1187 int b;
1188 int key;
1189 ui5b m;
1190
1191 for (j = 0; j < 16; ++j) {
1192 ui3b k1 = ((ui3b *)theKeys)[j];
1193 if (0 != k1) {
1194 ui3b bit = 1;
1195 for (b = 0; b < 8; ++b) {
1196 if (0 != (k1 & bit)) {
1197 key = j * 8 + b;
1198 switch (key) {
1199 case MKC_Control: m = kKeepMaskControl; break;
1200 case MKC_CapsLock: m = kKeepMaskCapsLock; break;
1201 case MKC_Command: m = kKeepMaskCommand; break;
1202 case MKC_Option: m = kKeepMaskOption; break;
1203 case MKC_Shift: m = kKeepMaskShift; break;
1204 default: m = 0; break;
1205 }
1206 if (0 == (KeepMask & m)) {
1207 Keyboard_UpdateKeyMap(key, falseblnr);
1208 }
1209 }
1210 bit <<= 1;
1211 }
1212 }
1213 }
1214}
1215
1216LOCALPROC MyEvtQTryRecoverFromFull(void)
1217{
1218 MyMouseButtonSet(falseblnr);
1219 DisconnectKeyCodes(0);
1220}
1221
1222/* MacMsg */
1223
1224LOCALVAR char *SavedBriefMsg = nullpr;
1225LOCALVAR char *SavedLongMsg;
1226#if WantAbnormalReports
1227LOCALVAR ui4r SavedIDMsg = 0;
1228#endif
1229LOCALVAR blnr SavedFatalMsg;
1230
1231LOCALPROC MacMsg(char *briefMsg, char *longMsg, blnr fatal)
1232{
1233 if (nullpr != SavedBriefMsg) {
1234 /*
1235 ignore the new message, only display the
1236 first error.
1237 */
1238 } else {
1239 SavedBriefMsg = briefMsg;
1240 SavedLongMsg = longMsg;
1241 SavedFatalMsg = fatal;
1242 }
1243}
1244
1245#if WantAbnormalReports
1246GLOBALOSGLUPROC WarnMsgAbnormalID(ui4r id)
1247{
1248 MacMsg(kStrReportAbnormalTitle,
1249 kStrReportAbnormalMessage, falseblnr);
1250
1251 if (0 != SavedIDMsg) {
1252 /*
1253 ignore the new message, only display the
1254 first error.
1255 */
1256 } else {
1257 SavedIDMsg = id;
1258 }
1259}
1260#endif
1261
1262#if EmLocalTalk
1263
1264/*
1265 small and simple entropy pool
1266
1267 cryptographic rigor not claimed. or any rigor.
1268
1269 there is code for a serious implementation of an entropy
1270 pool in the Mini vMac extra "MakeRand" (adapted from
1271 MacPGP), but it seems massive overkill for the purpose
1272 here - minimizing the chance that two instances of
1273 Mini vMac pick the same LT_NodeHint and LT_MyStamp.
1274*/
1275
1276LOCALVAR ui5b e_p[2] = {
1277 0, 0
1278 };
1279
1280LOCALPROC EntropyPoolStir(void)
1281{
1282 /*
1283 mix up the bits in a way that doesn't lose information.
1284 that is, each of the 2**64 possible inputs leads to a
1285 different one of the 2**64 possible outputs.
1286
1287 to do: verify it actually does scramble things sufficiently,
1288 or modify it til it does.
1289 */
1290
1291 ui5b t0a = e_p[0];
1292 ui5b t1a = e_p[1];
1293
1294 ui5b t0b = t0a * 0xAE3CC725 + 0xD860D735;
1295 ui5b t1b = t1a * 0x9FE72885 + 0x641AD0A9;
1296 /*
1297 multiplication constants from
1298 "https://arxiv.org/abs/2001.05304",
1299 though not being used as intended. haven't
1300 really actually read the thing yet.
1301 addition constants are just random odd numbers.
1302 */
1303
1304 ui5b t0c = (t0b << 8) + (t1b >> 24);
1305 ui5b t1c = (t1b << 8) + (t0b >> 24);
1306
1307 e_p[0] = t0c;
1308 e_p[1] = t1c;
1309}
1310
1311LOCALPROC EntropyPoolAddByte(ui3r v)
1312{
1313 e_p[0] += v;
1314 e_p[1] += v;
1315
1316 EntropyPoolStir();
1317}
1318
1319LOCALPROC EntropyPoolAddPtr(ui3p p, uimr n)
1320{
1321 uimr i;
1322
1323 for (i = n + 1; 0 != --i; ) {
1324 EntropyPoolAddByte(*p++);
1325 }
1326
1327#if dbglog_HAVE
1328 dbglog_writeCStr("ep: ");
1329 dbglog_writeHex(e_p[0]);
1330 dbglog_writeCStr(" ");
1331 dbglog_writeHex(e_p[1]);
1332 dbglog_writeReturn();
1333#endif
1334}
1335
1336
1337
1338LOCALVAR ui5b LT_MyStamp = 0;
1339 /*
1340 randomly chosen value included in sent packets.
1341 if received packets have different value, then know it
1342 is from somebody else. (but if it is same value, don't
1343 know for sure it isn't from somebody else.)
1344 */
1345
1346LOCALPROC LT_PickStampNodeHint(void)
1347{
1348 LT_MyStamp = e_p[0];
1349
1350#if dbglog_HAVE && 1
1351 dbglog_writelnNum("LT_MyStamp ", LT_MyStamp);
1352#endif
1353
1354#if 0
1355 LT_NodeHint = 1; /* for testing collision handling */
1356#else
1357 {
1358 int i = 8 + 1;
1359
1360label_retry:
1361 /* user node should be in 1-127 */
1362
1363 LT_NodeHint = e_p[1] & 0x7F;
1364
1365#if dbglog_HAVE && 1
1366 dbglog_writelnNum("LT_NodeHint ", LT_NodeHint);
1367#endif
1368
1369 if (0 != LT_NodeHint) {
1370 /* ok */
1371 } else
1372 if (0 == --i) {
1373 /* just maybe, randomness is broken */
1374 /*
1375 fall back to a different random number generater:
1376 https://xkcd.com/221/
1377 */
1378 LT_NodeHint = 4;
1379 } else
1380 {
1381 EntropyPoolStir();
1382
1383 goto label_retry;
1384 }
1385 }
1386#endif
1387}
1388
1389#endif /* EmLocalTalk */