1 /**************************************************************************************\
2 *                                                                                      *
3 *              The Lisa Emulator Project  V1.2.6      DEV 2007.12.04                   *
4 *                             http://lisaem.sunder.net                                 *
5 *                                                                                      *
6 *                  Copyright (C) 1998, 2007 Ray A. Arachelian                          *
7 *                                All Rights Reserved                                   *
8 *                                                                                      *
9 *           This program is free software; you can redistribute it and/or              *
10 *           modify it under the terms of the GNU General Public License                *
11 *           as published by the Free Software Foundation; either version 2             *
12 *           of the License, or (at your option) any later version.                     *
13 *                                                                                      *
14 *           This program is distributed in the hope that it will be useful,            *
15 *           but WITHOUT ANY WARRANTY; without even the implied warranty of             *
16 *           MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *
17 *           GNU General Public License for more details.                               *
18 *                                                                                      *
19 *           You should have received a copy of the GNU General Public License          *
20 *           along with this program;  if not, write to the Free Software               *
21 *           Foundation, Inc., 59 Temple Place #330, Boston, MA 02111-1307, USA.        *
22 *                                                                                      *
23 *                   or visit: http://www.gnu.org/licenses/gpl.html                     *
24 *                                                                                      *
25 \**************************************************************************************/
26 
27 
28 // RAW_BITMAP_ACCESS should be used in most cases as it proves much higher performance
29 #ifdef NO_RAW_BITMAP_ACCESS
30  #ifdef USE_RAW_BITMAP_ACCESS
31    #undef	USE_RAW_BITMAP_ACCESS
32  #endif
33 #endif
34 
35 #ifdef VERSION
36     static char *my_version=VERSION;
37 #endif
38 #ifdef BUILTBY
39  static char *my_built_by=BUILTBY;
40 #endif
41 
42 long emulation_tick=40;
43 long emulation_time=25;
44 
45 
46 // Some weird new changes to wxWidgets require newly created bitmaps to be filled,
47 // otherwise the wx/rawbmp.h code won't work right (since the alpha mask in the bitmap
48 // is set to the background, so we get no updates when we do the blit.  Yuck!)
49 //
50 // Worse yet, on some systems this needs to be WHITE creating annoying white flashes
51 // or white screens when LisaEm is off.  {Insert print "Motherfucker!" X 10000000}
52 
53 #define FILLERBRUSH  *wxBLACK_BRUSH
54 #define FILLERPEN    *wxBLACK_PEN
55 
56 
57 // How many changes on the display before refreshing the entire display instead of the updated area?
58 // want to keep this value small, otherwise a clear desktop or such will be very slow.  The idea here
59 // is to avoid full repaints on small changes, such as the mouse moving.
60 
61 #define DIRECT_BLITS_THRESHHOLD 64
62 
63 // How much more blue to add to simulate the blueish phosphor of the Lisa CRT
64 #define EXTRABLUE 15
65 // minimum skinned window size, this is smaller on purpose so that it will work with 12"
66 // notebook displays
67 #define IWINSIZEX 1020
68 #define IWINSIZEY 720
69 
70 #define IWINSIZE IWINSIZEX,IWINSIZEY
71 
72 // the size of the skin
73 #define ISKINSIZEX 1485
74 #define ISKINSIZEY 1031
75 #define ISKINSIZE  ISKINSIZEX,ISKINSIZEY
76 
77 #define FLOPPY_LEFT 1099
78 #define FLOPPY_TOP 481
79 
80 #define POWER_LEFT 0
81 #define POWER_TOP 738
82 
83 // padding for skinless mode
84 #define WINXDIFF 30
85 #define WINYDIFF 65
86 
87 // binary AND filter for how often to update
88 // the skinless background filter.  has to be 3,7,15,31,63
89 // larger the value the longer the delay between updates.
90 #define SKINLESS_UPDATE_FILTER 3
91 
92 
93 
94 #include <wx/wx.h>
95 #include <wx/defs.h>
96 #include <wx/image.h>
97 #include <wx/icon.h>
98 #include <wx/dcbuffer.h>
99 #include <wx/wxhtml.h>
100 #include <wx/fs_zip.h>
101 #include <wx/wfstream.h>
102 #include <wx/log.h>
103 #include <wx/filedlg.h>
104 #include <wx/fileconf.h>
105 #include <wx/statusbr.h>
106 #include <wx/scrolwin.h>
107 #include <wx/sound.h>
108 #include <wx/config.h>
109 #include <wx/clipbrd.h>
110 #include <wx/datetime.h>
111 #include <wx/stopwatch.h>
112 #include <wx/display.h>
113 #include <wx/gdicmn.h>
114 #include <wx/pen.h>
115 #include <wx/scrolwin.h>
116 #include <wx/notebook.h>
117 #include <wx/aboutdlg.h>
118 #include <wx/stdpaths.h>
119 #include <wx/choicdlg.h>
120 
121 #ifdef USE_RAW_BITMAP_ACCESS
122 #include <wx/rawbmp.h>
123 #endif
124 
125 #include "machine.h"
126 #include "keyscan.h"
127 
128 #include "LisaConfig.h"
129 #include "LisaConfigFrame.h"
130 
131 // sounds, images, etc.
132 #include "lisaem_static_resources.h"
133 
134 #ifdef __WXOSX__
135 #include <CoreFoundation/CoreFoundation.h>
136 #include <sys/param.h>
137 // was 32
138 #define DEPTH 32
139 #else
140 #define DEPTH 24
141 #endif
142 
143 
144 #ifndef MAXPATHLEN
145 #define MAXPATHLEN 1024
146 #endif
147 
148 extern "C"
149 {
150  #include "vars.h"
151  int32 reg68k_external_execute(int32 clocks);
152  void unvars(void);
153 
154 }
155 
156 #if wxUSE_UNICODE
157  #define CSTRCONV (wchar_t*)
158 #else
159  #define CSTRCONV (char*)
160 #endif
161 
162 
163 // fwd references.
164 extern "C" int ImageWriter_LisaEm_Init(int iwnum);
165 extern "C" void iw_formfeed(int iw);
166 extern "C" void ImageWriterLoop(int iw,uint8 c);
167 extern "C" void iw_shutdown(void);
168 
169 extern "C" void emulate (void);
170 extern "C" void XLLisaRedrawPixels(void);          // proto to supress warning below
171 extern "C" void LisaRedrawPixels(void);
172 
173 extern "C" void resume_run(void);
174 extern "C" void pause_run(void);
175 
176 extern "C" void force_refresh(void);
177 
178 extern "C" void iw_enddocuments(void);
179 
180 void iw_check_finish_job(void);
181 
182 
183 void turn_skins_on(void);
184 void turn_skins_off(void);
185 
186 void powerbutton(void);
187 void setvideomode(int mode);
188 void save_global_prefs(void);
189 
190 int asciikeyboard=1;
191 
192 #ifndef MIN
193   #define MIN(x,y) ( (x)<(y) ? (x):(y) )
194 #endif
195 
196 #ifndef MAX
197   #define MAX(x,y) ( (x)>(y) ? (x):(y) )
198 #endif
199 
200 
201 /*********************************************************************************************************************************/
202 
203 
204  extern "C" int cpu68k_init(void);
205  extern "C" void cpu68k_reset(void);
206  extern "C" uint8 evenparity(uint8 data);
207 
208 
209 
210 int effective_lisa_vid_size_y=500; //364;
211 int effective_lisa_vid_size_x=720;
212 
213 wxPaintEvent nada;
214 
215 void black(void);
216 
217 
218 // these need to be inside some sort of skin.rc file.
219 int screen_origin_x=140;
220 int screen_origin_y=130;
221 
222 
223 
224 wxConfigBase      *myConfig;             // default configuration (just a pointer to the active config)
225 wxString           myconfigfile;         // config filename
226 wxFileStream      *pConfigIS;            // config file
227 
228 
229 LisaConfigFrame  *my_LisaConfigFrame=NULL;
230 
231 void updateThrottleMenus(float throttle);
232 /*************************************************************************************************************************************/
233 
234 
235 // Declare the application class
236 class LisaEmApp : public wxApp
237 {
238 public:
239     // Called on application startup
240     virtual bool OnInit();
241     #ifndef __WXOSX__
242     void OnQuit(wxCommandEvent& event);
243     #endif
244 };
245 
246 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
247 
248 
249 #define FLOPPY_NEEDS_REDRAW    0x80
250 #define FLOPPY_ANIMATING       0x40
251 #define FLOPPY_INSERT_0        0x00
252 #define FLOPPY_INSERT_1        0x01
253 #define FLOPPY_INSERT_2        0x02
254 #define FLOPPY_PRESENT         0x03
255 #define FLOPPY_EMPTY           0x04
256 #define FLOPPY_ANIM_MASK       0x07
257 
258 #define POWER_NEEDS_REDRAW     0x80
259 #define POWER_PUSHED           0x40
260 #define POWER_ON_MASK          0x01
261 #define POWER_ON               0x01
262 #define POWER_OFF              0x00
263 
264 #define REPAINT_INVALID_WINDOW 0x80
265 #define REPAINT_POWER_TO_SKIN  0x04
266 #define REPAINT_FLOPPY_TO_SKIN 0x02
267 #define REPAINT_VIDEO_TO_SKIN  0x01
268 #define REPAINT_NOTHING        0x00
269 
270 
271 class LisaWin : public wxScrolledWindow
272 {
273 public:
274      LisaWin(wxWindow *parent);
275      ~LisaWin();
276 
277      int dirtyscreen;      // indicated dirty lisa vidram
278      int doubley;
279      uint8 brightness;
280 
281      int refresh_bytemap;  // flag indicating contrast change
282      int floppystate;      // animation state of floppy
283      int powerstate;       // animation state of power button
284 
285 
286      void RePaint_AAGray(void);
287      void RePaint_AntiAliased(void);
288 
289      void RePaint_DoubleY(void);
290      void RePaint_SingleY(void);
291      //void RePaint_Scaled(void);
292      void RePaint_3A(void);
293      void RePaint_2X3Y(void);
294 
295      void (LisaWin::*RePainter)(void);   // pointer method to one of the above
296 
297 
298      void SetVideoMode(int mode);
299 
300      void OnPaint_skinless(wxRect &rect);
301      void OnPaint_skins(wxRect &rect);
302      void OnPaint(wxPaintEvent &event);
303 
304      void OnErase(wxEraseEvent &event);
305 
306 	 long mousemoved;
307 
308      void OnMouseMove(wxMouseEvent &event);
309      void OnKeyDown(wxKeyEvent& event);
310      void OnKeyUp(wxKeyEvent& event);
311      void OnChar(wxKeyEvent& event);
312 
313      void LogKeyEvent(const wxChar *name, wxKeyEvent& event,int keydir);
314      void ContrastChange(void);
315 
316      int lastkeystroke;
317 
318 
319      int repaintall;
320      int ox,oy,ex,ey;
321      int dwx,dwy;
322 
323      int rawcodes[128];
324      int rawidx;
325 
326      uint8 bright[16];       // brightness levels for ContrastChange and repaint routines.
327 
328 private:
329      int lastkeyevent;
330      wxScrolledWindow *myparent;
331      wxCursor *m_dot_cursor;
332      int lastcontrast;
GetChar(bool on,wxChar c)333      static inline wxChar GetChar(bool on, wxChar c) { return on ? c : _T('-'); }
334 
335      DECLARE_EVENT_TABLE()
336 };
337 
338 
339 
340 BEGIN_EVENT_TABLE(LisaWin, wxScrolledWindow)
341 
342     EVT_KEY_DOWN(LisaWin::OnKeyDown)
343     EVT_KEY_UP(LisaWin::OnKeyUp)
344     EVT_CHAR(LisaWin::OnChar)
345 
346     EVT_ERASE_BACKGROUND(LisaWin::OnErase)
347     EVT_PAINT(LisaWin::OnPaint)
348     EVT_MOTION(LisaWin::OnMouseMove)
349     EVT_LEFT_DOWN(LisaWin::OnMouseMove)
350     EVT_LEFT_UP(LisaWin::OnMouseMove)
351     EVT_RIGHT_DOWN(LisaWin::OnMouseMove)
352     EVT_RIGHT_UP(LisaWin::OnMouseMove)
353 
354 END_EVENT_TABLE()
355 
356 
357 // Event table for LisaEmFrame
358 enum
359 {
360     ID_SCREENSHOT=10001,           // anti-aliased screenshot
361     ID_SCREENSHOT2,                // screenshot with screen
362     ID_SCREENSHOT3,                // raw screenshot - no aliasing
363 
364     ID_FUSH_PRNT,
365 
366 #ifndef __WXMSW__
367 #ifdef TRACE
368     ID_DEBUG,
369 #endif
370 #endif
371 
372     ID_DEBUGGER,
373     ID_POWERKEY,
374     ID_APPLEPOWERKEY,
375 
376     ID_KEY_APL_DOT,
377     ID_KEY_APL_S,
378     ID_KEY_APL_ENTER,
379     ID_KEY_APL_RENTER,
380     ID_KEY_APL_1,
381     ID_KEY_APL_2,
382     ID_KEY_APL_3,
383     ID_KEY_NMI,
384 
385 	ID_KEY_RESET,
386 
387     ID_PROFILEPWR,
388 
389     ID_PROFILE_ALL_ON,
390     ID_PROFILE_ALL_OFF,
391 
392     ID_PROFILE_S1L,
393     ID_PROFILE_S1U,
394     ID_PROFILE_S2L,
395     ID_PROFILE_S2U,
396     ID_PROFILE_S3L,
397     ID_PROFILE_S3U,
398 
399     ID_PROFILE_NEW,
400 
401     ID_FLOPPY,
402     ID_NewFLOPPY,
403 
404     ID_RUN,
405     ID_PAUSE,
406 
407     ID_KEY_OPT_0,
408     ID_KEY_OPT_4,
409     ID_KEY_OPT_7,
410     ID_KEYBOARD,
411     ID_ASCIIKB,
412     ID_RAWKB,
413     ID_RAWKBBUF,
414 
415     ID_EMULATION_TIMER,
416 
417     ID_THROTTLE5,
418     ID_THROTTLE8,
419     ID_THROTTLE10,
420     ID_THROTTLE12,
421     ID_THROTTLE16,
422     ID_THROTTLE32,
423     ID_THROTTLEX,
424 
425     ID_ET100_75,
426     ID_ET50_30,
427     ID_ET40_25,
428     ID_ET30_20,
429 
430     ID_LISAWEB,
431     ID_LISAFAQ,
432 
433     ID_VID_AA,
434     ID_VID_AAG,
435     //ID_VID_SCALED,
436     ID_VID_DY,
437     ID_VID_SY,
438     ID_VID_2X3Y,
439 
440   // reinstated as per request by Kallikak
441     ID_REFRESH_60Hz,
442     ID_REFRESH_20Hz,
443     ID_REFRESH_12Hz,
444     ID_REFRESH_8Hz,
445     ID_REFRESH_4Hz,
446 
447     ID_HIDE_HOST_MOUSE,
448 
449     ID_VID_SKINS_ON,
450     ID_VID_SKINS_OFF
451 };
452 
453 // Declare our main frame class
454 
455 
456 
457 // lisaframe::running states
458 enum
459 {
460 	emulation_off=0,
461 	emulation_running=1,
462 	emulation_paused=10
463 };
464 
465 class LisaEmFrame : public wxFrame
466 {
467 public:
468 
469     int running;          // is the Lisa running?  0=off, 1=running, 10=paused/locked.
470 
471     // Constructor
472     LisaEmFrame(const wxString& title);
473 
474     void LoadImages(void);
475     void UnloadImages(void);
476 
477     // Event handlers
478     #ifdef __WXOSX__
479     void OnQuit(wxCommandEvent& event);
480     #endif
481 
482     void OnAbout(wxCommandEvent& event);
483 
484     void OnLisaWeb(wxCommandEvent& event);
485     void OnLisaFaq(wxCommandEvent& event);
486 
487     void OnConfig(wxCommandEvent& event);
488     void OnOpen(wxCommandEvent& event);
489     void OnSaveAs(wxCommandEvent& event);
490 
491 
492     void OnRun(wxCommandEvent& event);
493     void OnPause(wxCommandEvent& event);
494 
495     void OnScreenshot(wxCommandEvent& event);
496     void OnDebugger(wxCommandEvent& event);
497 
498     void OnPOWERKEY(wxCommandEvent& event);
499     void OnAPPLEPOWERKEY(wxCommandEvent& event);
500     void OnTraceLog(wxCommandEvent& event);
501     void OnKEY_APL_DOT(wxCommandEvent& event);
502     void OnKEY_APL_S(wxCommandEvent& event);
503     void OnKEY_APL_ENTER(wxCommandEvent& event);
504     void OnKEY_APL_RENTER(wxCommandEvent& event);
505     void OnKEY_APL_1(wxCommandEvent& event);
506     void OnKEY_APL_2(wxCommandEvent& event);
507     void OnKEY_APL_3(wxCommandEvent& event);
508     void OnKEY_NMI(wxCommandEvent& event);
509 	void OnKEY_RESET(wxCommandEvent& event);
510 
511 
512 	void UpdateProfileMenu(void);
513 	void OnProFilePowerX(int bit);
514 
515 	void OnProFilePower(wxCommandEvent& event);
516 
517     void OnProFilePwrOnAll(wxCommandEvent& event);
518 	void OnProFilePwrOffAll(wxCommandEvent& event);
519 
520     void OnProFileS1LPwr(wxCommandEvent& event);
521     void OnProFileS1UPwr(wxCommandEvent& event);
522     void OnProFileS2LPwr(wxCommandEvent& event);
523     void OnProFileS2UPwr(wxCommandEvent& event);
524     void OnProFileS3LPwr(wxCommandEvent& event);
525     void OnProFileS3UPwr(wxCommandEvent& event);
526 
527 	void OnNewProFile(wxCommandEvent& event);
528 
529 
530 
531 
532 
533     void OnFLOPPY(wxCommandEvent& event);
534     void OnNewFLOPPY(wxCommandEvent& event);
535 
536     void OnxFLOPPY(void);
537     void OnxNewFLOPPY(void);
538 
539     void OnKEY_OPT_0(wxCommandEvent& event);
540     void OnKEY_OPT_4(wxCommandEvent& event);
541     void OnKEY_OPT_7(wxCommandEvent& event);
542     void OnKEYBOARD(wxCommandEvent& event);
543 
544     void OnASCIIKB(wxCommandEvent& event);
545     void OnRAWKB(wxCommandEvent& event);
546     void OnRAWKBBUF(wxCommandEvent& event);
547     void reset_throttle_clock(void);
548 
549     void OnThrottle5(wxCommandEvent& event);
550     void OnThrottle8(wxCommandEvent& event);
551     void OnThrottle10(wxCommandEvent& event);
552     void OnThrottle12(wxCommandEvent& event);
553     void OnThrottle16(wxCommandEvent& event);
554     void OnThrottle32(wxCommandEvent& event);
555     void OnThrottleX(wxCommandEvent& event);
556 
557     void OnET100_75(wxCommandEvent& event);
558     void OnET50_30(wxCommandEvent& event);
559     void OnET40_25(wxCommandEvent& event);
560     void OnET30_20(wxCommandEvent& event);
561 
562     void SetStatusBarText(wxString &msg);
563     void Update_Status(long elapsed,long idleentry);
564     void VidRefresh(long now);
565 	int EmulateLoop(long idleentry);
566 
567     //void OnIdleEvent(wxIdleEvent& event);
568     void OnEmulationTimer(wxTimerEvent& event);
569 
570 	void OnPasteToKeyboard(wxCommandEvent&event);
571 
572 
573 	void FloppyAnimation(void);
574     // menu commands that switch video mode
575     void OnVideoAntiAliased(wxCommandEvent& event);
576     void OnVideoAAGray(wxCommandEvent& event);
577     //void OnVideoScaled(wxCommandEvent& event);
578     void OnVideoDoubleY(wxCommandEvent& event);
579     void OnVideoSingleY(wxCommandEvent& event);
580     void OnVideo2X3Y(wxCommandEvent& event);
581 
582     void OnSkinsOn(wxCommandEvent& event);
583     void OnSkinsOff(wxCommandEvent& event);
584 
585     void OnRefresh60Hz(wxCommandEvent& event);
586     void OnRefresh20Hz(wxCommandEvent& event);
587     void OnRefresh12Hz(wxCommandEvent& event);
588     void OnRefresh8Hz(wxCommandEvent& event);
589     void OnRefresh4Hz(wxCommandEvent& event);
590 
591     void OnFlushPrint(wxCommandEvent& event);
592     void OnHideHostMouse(wxCommandEvent& event);
593 
594 
595 
596     //class LisaWin *win;
597     int screensizex,screensizey;
598     int depth;
599 
600     wxStopWatch runtime;               // idle loop stopwatch
601     wxStopWatch soundsw;
602     int soundplaying;
603 
604     uint16 lastt2;
605     long    last_runtime_sample;
606     long    last_decisecond;
607     XTIMER clx;
608     XTIMER lastclk;
609     XTIMER cpu68k_reference;
610     XTIMER last_runtime_cpu68k_clx;
611     int dwx,dwy;
612 
613     wxString       wspaste_to_keyboard;
614     char          paste_to_keyboard[8192];
615     uint32         idx_paste_to_kb;
616     float          throttle;
617     float          clockfactor;
618     float          mhzactual;
619 
620     wxString floppy_to_insert;
621     long lastcrtrefresh;
622 	long hostrefresh;
623 	long screen_paint_update;
624     long onidle_calls;
625     XTIMER cycles_wanted;
626 
627     wxTimer* m_emulation_timer;
628     int barrier;
629     DECLARE_EVENT_TABLE()
630 };
631 
632 BEGIN_EVENT_TABLE(LisaEmFrame, wxFrame)
633 
634 
635     EVT_MENU(wxID_ABOUT,        LisaEmFrame::OnAbout)
636 
637 
638     EVT_MENU(ID_LISAWEB,        LisaEmFrame::OnLisaWeb)
639     EVT_MENU(ID_LISAFAQ,        LisaEmFrame::OnLisaFaq)
640 
641 
642     EVT_MENU(wxID_PREFERENCES,  LisaEmFrame::OnConfig)
643     EVT_MENU(wxID_OPEN,         LisaEmFrame::OnOpen)
644     EVT_MENU(wxID_SAVEAS,       LisaEmFrame::OnSaveAs)
645 
646     EVT_MENU(ID_SCREENSHOT,     LisaEmFrame::OnScreenshot)
647     EVT_MENU(ID_SCREENSHOT2,    LisaEmFrame::OnScreenshot)
648     EVT_MENU(ID_SCREENSHOT3,    LisaEmFrame::OnScreenshot)
649 
650     EVT_MENU(ID_FUSH_PRNT,      LisaEmFrame::OnFlushPrint)
651 
652     EVT_MENU(ID_DEBUGGER,       LisaEmFrame::OnDebugger)
653     EVT_MENU(ID_POWERKEY,       LisaEmFrame::OnPOWERKEY)
654     EVT_MENU(ID_APPLEPOWERKEY,  LisaEmFrame::OnAPPLEPOWERKEY)
655 
656 
657 #ifndef __WXMSW__
658 #ifdef TRACE
659     EVT_MENU(ID_DEBUG,          LisaEmFrame::OnTraceLog)
660 #endif
661 #endif
662 
663 
664     EVT_MENU(ID_KEY_APL_DOT,    LisaEmFrame::OnKEY_APL_DOT)
665     EVT_MENU(ID_KEY_APL_S,      LisaEmFrame::OnKEY_APL_S)
666     EVT_MENU(ID_KEY_APL_ENTER,  LisaEmFrame::OnKEY_APL_ENTER)
667     EVT_MENU(ID_KEY_APL_RENTER, LisaEmFrame::OnKEY_APL_RENTER)
668     EVT_MENU(ID_KEY_APL_1,      LisaEmFrame::OnKEY_APL_1)
669     EVT_MENU(ID_KEY_APL_2,      LisaEmFrame::OnKEY_APL_2)
670     EVT_MENU(ID_KEY_APL_3,      LisaEmFrame::OnKEY_APL_3)
671     EVT_MENU(ID_KEY_NMI,        LisaEmFrame::OnKEY_NMI)
672     EVT_MENU(ID_KEY_RESET,      LisaEmFrame::OnKEY_RESET)
673 
674     EVT_MENU(ID_PROFILEPWR,     LisaEmFrame::OnProFilePower)
675 
676     EVT_MENU(ID_PROFILE_ALL_ON, LisaEmFrame::OnProFilePwrOnAll)
677 	EVT_MENU(ID_PROFILE_ALL_OFF,LisaEmFrame::OnProFilePwrOffAll)
678 
679     EVT_MENU(ID_PROFILE_S1L,    LisaEmFrame::OnProFileS1LPwr)
680     EVT_MENU(ID_PROFILE_S1U,    LisaEmFrame::OnProFileS1UPwr)
681     EVT_MENU(ID_PROFILE_S2L,    LisaEmFrame::OnProFileS2LPwr)
682     EVT_MENU(ID_PROFILE_S2U,    LisaEmFrame::OnProFileS2UPwr)
683     EVT_MENU(ID_PROFILE_S3L,    LisaEmFrame::OnProFileS3LPwr)
684     EVT_MENU(ID_PROFILE_S3U,    LisaEmFrame::OnProFileS3UPwr)
685 
686     EVT_MENU(ID_PROFILE_NEW,    LisaEmFrame::OnNewProFile)
687 
688 
689     EVT_MENU(ID_FLOPPY,         LisaEmFrame::OnFLOPPY)
690     EVT_MENU(ID_NewFLOPPY,      LisaEmFrame::OnNewFLOPPY)
691 
692     EVT_MENU(ID_KEY_OPT_0,      LisaEmFrame::OnKEY_OPT_0)
693     EVT_MENU(ID_KEY_OPT_4,      LisaEmFrame::OnKEY_OPT_4)
694     EVT_MENU(ID_KEY_OPT_7,      LisaEmFrame::OnKEY_OPT_7)
695 
696     EVT_MENU(ID_KEYBOARD,       LisaEmFrame::OnKEYBOARD)
697     EVT_MENU(ID_ASCIIKB,        LisaEmFrame::OnASCIIKB)
698     EVT_MENU(ID_RAWKB,          LisaEmFrame::OnRAWKB)
699     EVT_MENU(ID_RAWKBBUF,       LisaEmFrame::OnRAWKBBUF)
700 
701     EVT_MENU(ID_THROTTLE5,      LisaEmFrame::OnThrottle5)
702     EVT_MENU(ID_THROTTLE8,      LisaEmFrame::OnThrottle8)
703     EVT_MENU(ID_THROTTLE10,     LisaEmFrame::OnThrottle10)
704     EVT_MENU(ID_THROTTLE12,     LisaEmFrame::OnThrottle12)
705     EVT_MENU(ID_THROTTLE16,     LisaEmFrame::OnThrottle16)
706     EVT_MENU(ID_THROTTLE32,     LisaEmFrame::OnThrottle32)
707     EVT_MENU(ID_THROTTLEX,      LisaEmFrame::OnThrottleX)
708 
709 
710     EVT_MENU(ID_ET100_75,       LisaEmFrame::OnET100_75)
711     EVT_MENU(ID_ET50_30,        LisaEmFrame::OnET50_30)
712     EVT_MENU(ID_ET40_25,        LisaEmFrame::OnET40_25)
713     EVT_MENU(ID_ET30_20,        LisaEmFrame::OnET30_20)
714 
715     EVT_MENU(wxID_PASTE,        LisaEmFrame::OnPasteToKeyboard)
716 
717 
718     EVT_MENU(ID_VID_AA,         LisaEmFrame::OnVideoAntiAliased)
719     EVT_MENU(ID_VID_AAG,        LisaEmFrame::OnVideoAAGray)
720 
721     //EVT_MENU(ID_VID_SCALED,     LisaEmFrame::OnVideoScaled)
722 
723 
724 
725     EVT_MENU(ID_VID_DY,         LisaEmFrame::OnVideoDoubleY)
726     EVT_MENU(ID_VID_SY,         LisaEmFrame::OnVideoSingleY)
727     EVT_MENU(ID_VID_2X3Y,       LisaEmFrame::OnVideo2X3Y)
728 
729     EVT_MENU(ID_VID_SKINS_ON,   LisaEmFrame::OnSkinsOn)
730     EVT_MENU(ID_VID_SKINS_OFF,  LisaEmFrame::OnSkinsOff)
731 
732   // reinstated as per request by Kallikak, added 4Hz to help with really slow machines
733     EVT_MENU(ID_REFRESH_60Hz,   LisaEmFrame::OnRefresh60Hz)
734     EVT_MENU(ID_REFRESH_20Hz,   LisaEmFrame::OnRefresh20Hz)
735     EVT_MENU(ID_REFRESH_12Hz,   LisaEmFrame::OnRefresh12Hz)
736     EVT_MENU(ID_REFRESH_8Hz,    LisaEmFrame::OnRefresh8Hz)
737     EVT_MENU(ID_REFRESH_4Hz,    LisaEmFrame::OnRefresh4Hz)
738 
739     EVT_MENU(ID_HIDE_HOST_MOUSE,LisaEmFrame::OnHideHostMouse)
740 
741     EVT_MENU(ID_RUN,            LisaEmFrame::OnRun)
742     EVT_MENU(ID_PAUSE,          LisaEmFrame::OnPause)
743 
744 
745     //EVT_IDLE(LisaEmFrame::OnIdleEvent)
746     EVT_TIMER(ID_EMULATION_TIMER, LisaEmFrame::OnEmulationTimer)
747 
748     #ifdef __WXOSX__
749     EVT_MENU(wxID_EXIT,         LisaEmFrame::OnQuit)
750     #else
751     EVT_MENU(wxID_EXIT,         LisaEmApp::OnQuit)
752     #endif
753 
754 
755 
756 
757 END_EVENT_TABLE()
758 
759 
760 // want to have these as globals so that they can be accessed by other fn's
761 // and passed around like a cheap 40oz bottle at a frat.
762 
763 wxFileConfig     *pConfig =NULL;
764 
765 
766 wxMenu *fileMenu     = NULL;
767 wxMenu *editMenu     = NULL;
768 wxMenu *keyMenu      = NULL;
769 wxMenu *DisplayMenu  = NULL;
770 wxMenu *throttleMenu = NULL;
771 wxMenu *profileMenu  = NULL;
772 
773 wxMenu *helpMenu     = NULL;
774 
775 
776 LisaConfig       *my_lisaconfig=NULL;
777 
778 LisaWin          *my_lisawin=NULL;
779 LisaEmFrame      *my_lisaframe=NULL;
780 
781 
782 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
783 
784 
785 //char *getResourcesDir(void)
786 //{
787 //    static char ret[1024];
788 //
789 //    wxStandardPathsBase& stdp = wxStandardPaths::Get();
790 //    strncpy(ret,stdp.GetResourcesDir().c_str(),1024);
791 //
792 //    return ret;
793 //}
794 //
795 //
796 //
797 //char *getDocumentsDir(void)
798 //{
799 //    static char ret[1024];
800 //
801 //    wxStandardPathsBase& stdp = wxStandardPaths::Get();
802 //    strncpy(ret,stdp.GetDocumentsDir().c_str(),1024);
803 //
804 //    return ret;
805 //}
806 //
807 // does not exist in wx2.7.x //
808 /*char *getExecutablePath(void)
809 {
810     static char ret[1024];
811 
812     wxStandardPathsBase& stdp = wxStandardPaths::Get();
813     strncpy(ret,stdp.GetExecutablePath().c_str(),1024);
814 
815     return ret;
816 }
817 */
818 
819 #ifndef USE_RAW_BITMAP_ACCESS
820 wxImage *display_img = NULL;
821 #endif
822 
823 wxMenuBar        *menuBar = NULL;
824 
825 wxBitmap         *my_lisabitmap=NULL;
826 wxMemoryDC       *my_memDC=NULL;
827 
828 wxSound          *my_lisa_sound=NULL;       // sounds generated by Lisa Speaker
829 
830 wxSound          *my_floppy_eject=NULL;
831 wxSound          *my_floppy_insert=NULL;
832 wxSound          *my_floppy_motor1=NULL;
833 wxSound          *my_floppy_motor2=NULL;
834 wxSound          *my_lisa_power_switch01=NULL;
835 wxSound          *my_lisa_power_switch02=NULL;
836 wxSound          *my_poweroffclk=NULL;
837 
838 
839 
840 
841 // byte bitmap used to accelerate writes to videoram
842 wxBitmap  *my_bytemap=NULL;    wxMemoryDC *my_bytemapDC =NULL;
843 wxBitmap  *my_alias  =NULL;    wxMemoryDC *my_aliasDC   =NULL;
844 
845 wxImage   *display_image =NULL;
846 
847 wxBitmap  *my_skin   =NULL;    wxMemoryDC *my_skinDC    =NULL; // bug with wxX11 turns background black, this attempts
848 wxBitmap  *my_skin0  =NULL;    wxMemoryDC *my_skin0DC   =NULL; // to split the img in two hoping that it will help.
849 wxBitmap  *my_skin1  =NULL;    wxMemoryDC *my_skin1DC   =NULL;
850 wxBitmap  *my_skin2  =NULL;    wxMemoryDC *my_skin2DC   =NULL;
851 wxBitmap  *my_skin3  =NULL;    wxMemoryDC *my_skin3DC   =NULL;
852 
853 wxBitmap  *my_floppy0=NULL;    wxMemoryDC *my_floppy0DC =NULL;
854 wxBitmap  *my_floppy1=NULL;    wxMemoryDC *my_floppy1DC =NULL;
855 wxBitmap  *my_floppy2=NULL;    wxMemoryDC *my_floppy2DC =NULL;
856 wxBitmap  *my_floppy3=NULL;    wxMemoryDC *my_floppy3DC =NULL;
857 wxBitmap  *my_floppy4=NULL;    wxMemoryDC *my_floppy4DC=NULL;
858 
859 wxBitmap  *my_poweron  =NULL;  wxMemoryDC *my_poweronDC =NULL;
860 wxBitmap  *my_poweroff =NULL;  wxMemoryDC *my_poweroffDC=NULL;
861 
862 
863 // display lens
864 static wxCoord screen_y_map[502];
865 static wxCoord screen_to_mouse[364*3];    // 2X,3Y mode is the largest we can do
866 static int     yoffset[502];              // lookup table for pointer into video display (to prevent multiplication)
867 
868 //static int     screen_focus[364*3];       // how close to the ideal pixel we are - is this still used?
869 
870 
buildscreenymap(void)871 void buildscreenymap(void)
872 {
873  float f,yf, ratio=364.0/500.0;
874  int i,yy;
875  wxCoord y;
876 
877 
878  for (y=0; y<364; y++) yoffset[y]=y*90;
879 
880  for (f=0.0,i=0; i<502; i++,f+=1.0)
881      {
882        yf=(f*ratio);
883        yy=(int)(yf); y=(wxCoord)yy;
884 
885        //screen_focus[i]=((int)(yf*10)) % 10;
886 
887        y=(y<499) ? y:499;
888        screen_to_mouse[i]=y;
889           screen_y_map[y]=i;
890      }
891 
892 }
893 
894 
buildscreenymap_raw(void)895 void buildscreenymap_raw(void)
896 {
897  wxCoord y;
898  for (y=0; y<364; y++)
899      {
900        yoffset[y]=y*90;
901        //screen_focus[y]=0;
902        screen_to_mouse[y]=y;
903           screen_y_map[y]=y;
904      }
905 
906 }
907 
buildscreenymap_3A(void)908 void buildscreenymap_3A(void)
909 {
910  wxCoord y;
911 
912  for (y=0; y<431; y++)
913      {
914        yoffset[y]=y*76;
915        //screen_focus[y]=0;
916        screen_to_mouse[y]=y;
917           screen_y_map[y]=y;
918      }
919 
920 }
921 
922 
buildscreenymap_2Y(void)923 void buildscreenymap_2Y(void)
924 {
925  wxCoord y;
926  for (y=0; y<364; y++)   yoffset[y]=y*90;
927  for (y=0; y<364*2; y++)
928      {
929        //screen_focus[y]=0;
930        screen_to_mouse[y]=y>>1;
931           screen_y_map[y>>1]=y;
932      }
933 }
934 
935 
buildscreenymap_3Y(void)936 void buildscreenymap_3Y(void)
937 {
938  wxCoord y;
939  for (y=0; y<364; y++)   yoffset[y]=y*90;
940  for (y=0; y<364*3; y++)
941      {
942        //screen_focus[y]=0;
943 
944        screen_to_mouse[y]=y/3;
945           screen_y_map[y/3]=y-1;
946      }
947 
948 }
949 
950 
951 // hack to fix issues on linux - somehow this isn't quite what I'd want either.
952 // it's not too different from --without-rawbitmap due to the conversions, and slightly worse.
correct_my_skin(void)953 void correct_my_skin(void)
954 {
955 #ifdef __WXGTK__
956  #ifdef USE_RAW_BITMAP_ACCESS
957 
958   wxImage *display_image;
959   if (!my_skin) return;
960 
961   display_image= new wxImage(  my_skin->ConvertToImage());
962   delete my_skin;
963   my_skin=new wxBitmap(*display_image);
964   delete display_image;
965   if ( my_skinDC==NULL)  my_skinDC=new class wxMemoryDC;
966   my_skinDC->SelectObjectAsSource(*my_skin);
967  #endif
968 #endif
969 }
970 
971 
972 // hack to fix issues on linux
correct_my_lisabitmap(void)973 void correct_my_lisabitmap(void)
974 {
975 #ifdef __WXGTK__
976  #ifdef USE_RAW_BITMAP_ACCESS
977 
978   wxImage *display_image;
979   if (!my_lisabitmap) return;
980 
981   display_image= new wxImage(  my_lisabitmap->ConvertToImage());
982   delete my_lisabitmap;
983   my_lisabitmap=new wxBitmap(*display_image);
984   delete display_image;
985   if ( my_memDC==NULL)  my_memDC=new class wxMemoryDC;
986   my_memDC->SelectObjectAsSource(*my_lisabitmap);
987  #endif
988 #endif
989 }
990 
991 
992 
993 ///////////////
SetVideoMode(int mode)994 void LisaWin::SetVideoMode(int mode)
995 {
996   //int i;
997   black();
998 
999   if ( has_lisa_xl_screenmod)   mode= 0x3a;               // sanity fixes
1000   if (!has_lisa_xl_screenmod && mode==0x3a) mode=0;
1001   if (mode!=0x3a) lisa_ui_video_mode=mode;
1002 
1003 
1004   DisplayMenu->Check(ID_VID_AA    ,mode==0);  DisplayMenu->Enable(ID_VID_AA    ,mode!=0x3a);
1005   DisplayMenu->Check(ID_VID_AAG   ,mode==4);  DisplayMenu->Enable(ID_VID_AAG   ,mode!=0x3a);
1006   //DisplayMenu->Check(ID_VID_SCALED,mode==5);  DisplayMenu->Enable(ID_VID_SCALED,mode!=0x3a);
1007   DisplayMenu->Check(ID_VID_DY    ,mode==1);  DisplayMenu->Enable(ID_VID_DY    ,mode!=0x3a);
1008   DisplayMenu->Check(ID_VID_SY    ,mode==2);  DisplayMenu->Enable(ID_VID_SY    ,mode!=0x3a);
1009   DisplayMenu->Check(ID_VID_2X3Y  ,mode==3);  DisplayMenu->Enable(ID_VID_2X3Y  ,mode!=0x3a);
1010 
1011 
1012   switch (mode)
1013   {
1014 
1015    case 0:   buildscreenymap()    ;  screen_origin_x=140; screen_origin_y=130; effective_lisa_vid_size_x=720; effective_lisa_vid_size_y=500;
1016              RePainter=&LisaWin::RePaint_AntiAliased;                                                                    break;
1017 
1018    case 1:   buildscreenymap_2Y() ;  screen_origin_x=  0; screen_origin_y=  0; effective_lisa_vid_size_x=720; effective_lisa_vid_size_y=364*2;
1019              RePainter=&LisaWin::RePaint_DoubleY;                                                                        break;
1020 
1021    case 2:   buildscreenymap_raw();  screen_origin_x=140; screen_origin_y=198; effective_lisa_vid_size_x=720; effective_lisa_vid_size_y=364;
1022              RePainter=&LisaWin::RePaint_SingleY;                                                                        break;
1023 
1024    case 3:   buildscreenymap_3Y() ;  screen_origin_x=  0; screen_origin_y=  0; effective_lisa_vid_size_x=720*2; effective_lisa_vid_size_y=364*3;
1025              RePainter=&LisaWin::RePaint_2X3Y;                                                                           break;
1026 
1027    case 4:   buildscreenymap()    ;  screen_origin_x=140; screen_origin_y=130; effective_lisa_vid_size_x=720; effective_lisa_vid_size_y=500;
1028              RePainter=&LisaWin::RePaint_AAGray;                                                                         break;
1029 
1030  //case 5:   buildscreenymap()    ;  screen_origin_x=140; screen_origin_y=130; effective_lisa_vid_size_x=720; effective_lisa_vid_size_y=500;
1031  //          RePainter=&LisaWin::RePaint_Scaled;                                                                         break;
1032 
1033 
1034    case 0x3a: buildscreenymap_3A();
1035 
1036              lisa_vid_size_x=608;
1037              lisa_vid_size_y=431;
1038              effective_lisa_vid_size_x=608;
1039              effective_lisa_vid_size_y=431;
1040 
1041              screen_origin_x=140+56;
1042              screen_origin_y=130+34;
1043 
1044              lisa_vid_size_x=608;
1045              lisa_vid_size_y=431;
1046 
1047              lisa_vid_size_xbytes=76;
1048              has_lisa_xl_screenmod=1;
1049 
1050              RePainter=&LisaWin::RePaint_3A;
1051              break;
1052   }
1053 
1054    delete my_lisabitmap;
1055    delete my_memDC;
1056 
1057    my_memDC     =new class wxMemoryDC;
1058    my_lisabitmap=new class wxBitmap(effective_lisa_vid_size_x, effective_lisa_vid_size_y,DEPTH);
1059    my_memDC->SelectObjectAsSource(*my_lisabitmap);
1060    my_memDC->SetBrush(FILLERBRUSH);      my_memDC->SetPen(FILLERPEN);
1061    my_memDC->DrawRectangle(0 ,   0,   effective_lisa_vid_size_x, effective_lisa_vid_size_y);
1062    if (!my_memDC->IsOk()) ALERT_LOG(0,"my_memDC is not ok.");
1063    if (!my_lisabitmap->IsOk()) ALERT_LOG(0,"my_lisabitmap is not ok.");
1064 
1065 
1066    videoramdirty=32768;
1067 //   ALERT_LOG(0,"Done setting video mode to :%02x",mode);
1068 
1069    if (skins_on)
1070 	   {
1071          SetMinSize(wxSize(720,384));
1072          SetMaxSize(wxSize(ISKINSIZE));
1073          SetScrollbars(ISKINSIZEX/100, ISKINSIZEY/100,  100,100,  0,0,  true);
1074          EnableScrolling(true,true);
1075        }
1076    else
1077        {
1078          int x,y;
1079          GetSize(&x,&y);
1080          screen_origin_x=(x  - effective_lisa_vid_size_x)>>1;                 // center display
1081          screen_origin_y=(y  - effective_lisa_vid_size_y)>>1;                 // on skinless
1082          screen_origin_x= (screen_origin_x<0 ? 0:screen_origin_x);
1083          screen_origin_y= (screen_origin_y<0 ? 0:screen_origin_y);
1084          ox=screen_origin_x; oy=screen_origin_y;
1085 	   }
1086    Refresh(false,NULL);
1087    black();
1088 
1089 }
1090 
FloppyAnimation(void)1091 void LisaEmFrame::FloppyAnimation(void)
1092 {
1093 
1094     if (my_lisawin->floppystate & FLOPPY_ANIMATING)                           // go to next frame
1095 	{
1096 
1097 		if ((my_lisawin->floppystate & FLOPPY_ANIM_MASK)!= FLOPPY_PRESENT)
1098 		{
1099 			my_lisawin->floppystate++;
1100 			my_lisawin->floppystate |= FLOPPY_ANIMATING|FLOPPY_NEEDS_REDRAW;
1101 		}
1102 
1103 		if ((my_lisawin->floppystate & FLOPPY_ANIM_MASK)== FLOPPY_PRESENT)
1104 		{
1105 			my_lisawin->floppystate= FLOPPY_NEEDS_REDRAW | FLOPPY_PRESENT; // refresh, stop counting.
1106 			if (my_floppy_insert!=NULL && sound_effects_on) my_floppy_insert->Play(romless ? wxSOUND_SYNC:wxSOUND_ASYNC);
1107 		}
1108 	}
1109     else
1110 	{
1111 		if (my_floppy_eject!=NULL && sound_effects_on && (my_lisawin->floppystate & FLOPPY_ANIM_MASK)== FLOPPY_INSERT_2)
1112 			my_floppy_eject->Play(wxSOUND_ASYNC);
1113 
1114 		if ((my_lisawin->floppystate & FLOPPY_ANIM_MASK)==FLOPPY_INSERT_0)
1115 		{
1116 			my_lisawin->floppystate=FLOPPY_NEEDS_REDRAW | FLOPPY_EMPTY;
1117 		}
1118 		else
1119 		{
1120 			my_lisawin->floppystate--;  // go to previous frame
1121 			my_lisawin->floppystate |= FLOPPY_NEEDS_REDRAW;
1122 		}
1123 
1124 	}
1125     Refresh();
1126     wxMilliSleep(200);
1127 }
1128 
1129 
1130 
1131 
VidRefresh(long now)1132 void LisaEmFrame::VidRefresh(long now)
1133 {
1134 
1135 
1136     if (videoramdirty)
1137     {
1138   		  wxRect* rect=NULL;
1139 		  if (running) check_running_lisa_os();
1140 
1141           my_lisawin->dirtyscreen=2;
1142 		  // suspect that RefreshRect(rect,false) erases the background anyway on wxMac 2.8.x
1143 		  rect=new wxRect(screen_origin_x,           screen_origin_y,
1144 					  effective_lisa_vid_size_x, effective_lisa_vid_size_y);
1145           Refresh(false, rect);
1146           delete rect;
1147  		  lastcrtrefresh=now;                                      // and how long ago the last refresh happened
1148                                                                    // cheating a bit here to smooth out mouse movement.
1149     }
1150 
1151 	screen_paint_update++;                                   // used to figure out effective host refresh rate
1152 	lastrefresh=cpu68k_clocks;
1153     seek_mouse_event();
1154 }
1155 
EmulateLoop(long idleentry)1156 int LisaEmFrame::EmulateLoop(long idleentry)
1157 {
1158 
1159     long now=runtime.Time();
1160 
1161     while (now-idleentry<emulation_time && running)          // don't stay in OnIdleEvent for too long, else UI gets unresponsive
1162     {
1163 		long cpuexecms=(long)((float)(cpu68k_clocks-cpu68k_reference)*clockfactor); //68K CPU Execution in MS
1164 
1165 		if ( cpuexecms<=now  )                               // balance 68K CPU execution vs host time to honor throttle
1166 		{
1167             if (!cycles_wanted) cycles_wanted=(XTIMER)(float)(emulation_time/clockfactor);
1168             clx=clx+cycles_wanted;                           // add in any leftover cycles we didn't execute.
1169                                                              // but prevent it falling behind or jumping ahead
1170                                                              // too far.
1171             clx=MIN(clx,2*cycles_wanted  );
1172             clx=MAX(clx,  cycles_wanted/2);
1173 
1174             clx=reg68k_external_execute(clx);                // execute some 68K code
1175             // clx=reg68k_external_execute(clx);
1176 
1177 			now=runtime.Time();                              // find out how long we took
1178 
1179             if (pc24 & 1)                                    // lisa rebooted or just odd addr error?
1180 			{                                                // moved here to avoid stack leak
1181                 ALERT_LOG(0,"ODD PC!")
1182 				if (lisa_ram_safe_getlong(context,12) & 1)   // oddaddr vector is odd as well?
1183 				{
1184 					save_pram();                             // lisa has rebooted.
1185 					profile_unmount();
1186 					return 1;
1187 				}
1188 			}
1189 
1190 			get_next_timer_event();                          // handle any pending IRQ's/timer prep work
1191 
1192 //20071115                                                             // if we need to, refresh the display
1193 //#ifdef __WXOSX__
1194 //		VidRefresh(now);                                     // OS X, esp slower PPC's suffer if we use the if statement
1195 //#else
1196 		if (now-lastcrtrefresh>hostrefresh) VidRefresh(now); // but if we don't, Linux under X11 gets too slow.
1197         else seek_mouse_event();
1198 
1199 //#endif
1200 		}                                                    // loop if we didn't go over our time quota
1201 		else
1202 			break;                                           // else force exit, time quota is up
1203     } // exec loop  ////////////////////////////////////////////////////////////////////////////////////////////////////////////
1204 
1205 	return 0;	                                             // Lisa did not reboot, return 0
1206 }
1207 
1208 
1209 
Update_Status(long elapsed,long idleentry)1210 void LisaEmFrame::Update_Status(long elapsed,long idleentry)
1211 {
1212 	wxString text;
1213 	float hosttime=(float)(elapsed - last_runtime_sample);
1214 	mhzactual= 0.001 *
1215 		( (float)(cpu68k_clocks-last_runtime_cpu68k_clx))  / hosttime;
1216 
1217   //text.Printf("%1.2fMHz  %x%x:%x%x:%x%x.%x @%d/%08x vid:%1.2fHz%c  loop:%1.2fHz, mouse:%1.2fHz slice:%ldms, 68K:%lldcycles (%3.2f ms), %lld left, %lld wanted (%lld%%)",
1218     text.Printf(_T("%1.2fMHz  %x%x:%x%x:%x%x.%x @%d/%08x"),
1219 				mhzactual,
1220 				lisa_clock.hours_h,lisa_clock.hours_l,
1221 				lisa_clock.mins_h,lisa_clock.mins_l,
1222 				lisa_clock.secs_h,lisa_clock.secs_l,
1223 				lisa_clock.tenths,
1224                 context,pc24); //,
1225 
1226 				//(float)screen_paint_update*1000/hosttime,                 (videoramdirty ? 'D':' '),
1227 				//(float)onidle_calls       *1000/hosttime,
1228 				//(float)my_lisawin->mousemoved *1000/hosttime,
1229 				//elapsed-idleentry,
1230                 //cpu68k_clocks-last_runtime_cpu68k_clx,
1231                 //((clockfactor==0) ?(0.001 *     ((float)(cpu68k_clocks-last_runtime_cpu68k_clx))/mhzactual)
1232 				//                  :(clockfactor*((float)(cpu68k_clocks-last_runtime_cpu68k_clx)))           ),
1233 				//clx, cycles_wanted,
1234 				//100*clx/cycles_wanted
1235 			   //);
1236 
1237 	SetStatusBarText(text);
1238 	// these are independant of the execution loops on purpose, so that way we get a 2nd opinion as it were.
1239 	last_runtime_sample=elapsed;
1240 	last_runtime_cpu68k_clx=cpu68k_clocks;
1241     my_lisawin->mousemoved=0;
1242 	screen_paint_update=0;                              // reset statistics counters
1243 	onidle_calls=0;
1244 	idleentry--;                                       // eat warning when debug version isn't used.
1245 }
1246 
OnEmulationTimer(wxTimerEvent & WXUNUSED (event))1247 void LisaEmFrame::OnEmulationTimer(wxTimerEvent& WXUNUSED(event))
1248 {
1249 
1250   long now=runtime.Time();
1251   long idleentry=now;
1252 
1253   // we run the timer as fast as possible.  there's a chance that it will call this method
1254   // while another instance is in progress.  the barrier prevents this.  Since each call will take
1255   // a slightly different amount of time, I can't predict a good value for this, but want to call it
1256   // as often as possible for the higher MHz throttles, so this is needed.
1257 
1258   if (barrier)   {ALERT_LOG(0,"Re-entry detected!"); return;}
1259   barrier=1;
1260 
1261   onidle_calls++;
1262 
1263   if ((my_lisawin->floppystate & FLOPPY_ANIM_MASK) != FLOPPY_PRESENT &&
1264 	  (my_lisawin->floppystate & FLOPPY_ANIM_MASK) != FLOPPY_EMPTY )	  FloppyAnimation();
1265 
1266    if (running==emulation_running)
1267    {
1268 	 long int elapsed=0;
1269 
1270   //   if (floppy_6504_wait>0 && floppy_6504_wait<128) floppy_6504_wait--;
1271 
1272      if (!last_runtime_sample )                              // initialize slice timer
1273      {
1274         last_runtime_sample=now;
1275         last_decisecond=now;
1276         lastcrtrefresh=now;
1277 		last_runtime_cpu68k_clx=cpu68k_clocks;
1278      }
1279 
1280 
1281 	 if (cpu68k_clocks<10 && floppy_to_insert.Len())         // deferred floppy insert.
1282 	 {
1283            const char *s = floppy_to_insert.fn_str();
1284            int i=floppy_insert((char *)s);
1285            floppy_to_insert=_T("");
1286            if (i) eject_floppy_animation();
1287 	 }
1288 
1289 
1290     clktest = cpu68k_clocks;
1291  	clx=cpu68k_clocks;
1292 
1293 	long ticks=( now - last_decisecond );                    // update COPS 1/10th second clock.
1294 	while (ticks>100) {ticks-=100; decisecond_clk_tick(); last_decisecond=now;}
1295 
1296 
1297     if (EmulateLoop(now) )                                   // 68K execution
1298 	{
1299 		ALERT_LOG(0,"REBOOTED?");                            // Did we reboot?
1300 		lisa_rebooted();
1301         barrier=0;
1302 		return;
1303 	}
1304 
1305 	elapsed=runtime.Time();                                  // get time after exist of execution loop
1306 
1307 
1308 	if ( (elapsed - last_runtime_sample) > 1000  && running) // update status bar every 1000ms, and check print jobs too
1309 	{
1310 		   static int ctr;
1311            Update_Status(elapsed,idleentry);
1312 		   if ((ctr++)>9) {iw_check_finish_job(); ctr=0;}
1313     }
1314 
1315     // anything to paste to the keyboard?
1316     if (wspaste_to_keyboard.Len()<8102 && wspaste_to_keyboard.Len()>idx_paste_to_kb && (copsqueuelen>=0 && copsqueuelen<MAXCOPSQUEUE-8) )
1317         {DEBUG_LOG(0,"pasting to kb"); keystroke_cops( paste_to_keyboard[idx_paste_to_kb++] );}
1318 
1319    }
1320    else // we are not running, or we are paused, so yield and sleep a bit
1321    {
1322 
1323 	  last_runtime_sample=0;
1324 	  lastcrtrefresh=0;
1325    }
1326 
1327 
1328 
1329    #ifndef __WXOSX__
1330      {
1331 	  static unsigned int x;
1332 	  x++;
1333 	  if (x>15)  {
1334 		          x=0;
1335 		          videoramdirty=32768;
1336 			      Refresh(false,NULL);
1337 			     }
1338      }
1339    #endif
1340 
1341 
1342 barrier=0;
1343 }
1344 ///////////////////////
1345 
1346 
1347 
1348 
OnPasteToKeyboard(wxCommandEvent & WXUNUSED (event))1349 void LisaEmFrame::OnPasteToKeyboard(wxCommandEvent& WXUNUSED(event))
1350 {
1351     wxTextDataObject data;
1352     if (wxTheClipboard->Open())
1353     {
1354         if (wxTheClipboard->IsSupported(wxDF_TEXT))  wxTheClipboard->GetData(data);
1355         wxTheClipboard->Close();
1356 
1357         wxTheClipboard->UsePrimarySelection();
1358 
1359         if (wxTheClipboard->IsSupported(wxDF_TEXT))
1360         {
1361 
1362             wspaste_to_keyboard = (wxString)(data.GetText());
1363             strncpy(paste_to_keyboard,wspaste_to_keyboard.fn_str(),8192 );
1364             idx_paste_to_kb = 0;
1365         }
1366     }
1367 }
1368 
LisaWin(wxWindow * parent)1369 LisaWin::LisaWin(wxWindow *parent)
1370         : wxScrolledWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
1371                    wxRAISED_BORDER|wxVSCROLL|wxHSCROLL|wxWS_EX_PROCESS_IDLE
1372 #ifdef wxALWAYS_SHOW_SB
1373 |wxALWAYS_SHOW_SB
1374 #endif
1375 #ifdef wxMAXIMIZE
1376 |wxMAXIMIZE
1377 #endif
1378                                    )
1379 {
1380        mousemoved=0;
1381 
1382 	   floppystate = FLOPPY_NEEDS_REDRAW | FLOPPY_EMPTY; // set floppy state and force refresh
1383        powerstate = POWER_NEEDS_REDRAW;                  // set power state and force refresh
1384        //repaintall = REPAINT_NOTHING;
1385 
1386        repaintall = REPAINT_INVALID_WINDOW;
1387 
1388        rawidx=0;
1389 
1390        SetExtraStyle(wxWS_EX_PROCESS_IDLE );
1391 
1392        // deprecated // SetInitialBestSize(wxSize(IWINSIZE));
1393 
1394 	   //wxScreenDC theScreen;          // I know I do this in the frame too, but when this runs,
1395 	   int screensizex,screensizey;   // my_lisaframe is still null.
1396 	   //theScreen.GetSize(&screensizex,&screensizey);
1397 
1398 	   wxDisplaySize(&screensizex,&screensizey);
1399 
1400 	   // Grrr! OS X sometimes returns garbage here
1401 	   if (screensizex< 0 || screensizex>8192 || screensizey<0 || screensizey>2048)
1402 	         {
1403 		      ALERT_LOG(0,"Got Garbage lisawin Screen Size: %d,%d",screensizex,screensizey);
1404 		      screensizex=1024; screensizey=768;
1405 	         }
1406 	   else
1407 		     {
1408   		      if (my_lisaframe) {my_lisaframe->screensizex=screensizex;my_lisaframe->screensizey=screensizey;}
1409 //			  ALERT_LOG(0,"LisaWin - Screen size is:%d,%d",screensizex,screensizey);
1410 		     }
1411 
1412 
1413        if (skins_on)
1414        {
1415          SetMinSize(wxSize(720,384)); //IWINSIZE previously
1416          SetSize(wxSize(IWINSIZE));
1417          SetMaxSize(wxSize(ISKINSIZE));
1418          SetScrollbars(ISKINSIZEX/100, ISKINSIZEY/100,  100,100,  0,0,  true);
1419          EnableScrolling(true,true);
1420 
1421          screen_origin_x=140;
1422          screen_origin_y=130;
1423        }
1424        else  //------------------------ skinless ----------------------------------------------------
1425        {
1426          switch (lisa_ui_video_mode)
1427          {
1428                default:
1429                 case 0:   effective_lisa_vid_size_x=720;   effective_lisa_vid_size_y=500;      break;
1430                 case 1:   effective_lisa_vid_size_x=720;   effective_lisa_vid_size_y=364*2;    break;
1431                 case 2:   effective_lisa_vid_size_x=720;   effective_lisa_vid_size_y=364;      break;
1432                 case 3:   effective_lisa_vid_size_x=720*2; effective_lisa_vid_size_y=364*3;    break;
1433                 case 4:   effective_lisa_vid_size_x=720;   effective_lisa_vid_size_y=500;      break;
1434                 case 0x3a:effective_lisa_vid_size_x=608;   effective_lisa_vid_size_y=431;      break;
1435          }
1436 
1437 
1438 
1439          int x,y;
1440 
1441          y=myConfig->Read(_T("/lisawin/sizey"),(long)effective_lisa_vid_size_y);
1442          x=myConfig->Read(_T("/lisawin/sizex"),(long)effective_lisa_vid_size_x);
1443          if (x<=0 || x>4096 || y<=0 || y>2048) {x=effective_lisa_vid_size_x;y=effective_lisa_vid_size_y;}
1444 
1445 
1446          if (x>screensizex || y>screensizey)         // if the saved/defaults are too large correct them
1447             {
1448               x=MIN(effective_lisa_vid_size_x,screensizex-100);
1449               y=MIN(effective_lisa_vid_size_y,screensizey-150);
1450             }
1451 
1452 //         ALERT_LOG(0,"Setting lisawin size to:%d,%d effective:%d,%d",x,y,
1453 //                     effective_lisa_vid_size_x,effective_lisa_vid_size_y);
1454 
1455          SetMinSize(wxSize(720,384));
1456          SetClientSize(wxSize(x,y));                                                         // LisaWin //
1457          SetMaxSize(wxSize(ISKINSIZE));                                                      // LisaWin //
1458          GetClientSize(&dwx,&dwy);
1459          // Sometimes GetClientSize/SetClientSize return DIFFERNT values.  On OS X this causes the
1460          // Lisa window to GROW over time! m@+h3rf*(<R!!!  dwx/dwy is used to figure out the difference,
1461 		 // and then adjust to the size we want.  This is some sick shit that anyone has to code this way.
1462          dwx-=x; dwy-=y;
1463          SetClientSize(wxSize(x-dwx,y-dwy));                                                 // LisaWin //
1464          SetMinSize(wxSize(720,384));
1465          ox=(x  - effective_lisa_vid_size_x)/2;                                              // center display
1466          oy=(y  - effective_lisa_vid_size_y)/2;                                              // on skinless
1467          ox= (ox<0 ? 0:ox);
1468          oy= (oy<0 ? 0:oy);
1469 
1470          EnableScrolling(false,false);                                                       // LisaWin //
1471 
1472        } // --------------------------------------------------------------------------------------------------
1473 
1474 
1475        RePainter=&LisaWin::RePaint_AntiAliased;  //RePaint_AAGray;
1476 
1477        /* Draw the VNC-style dot cursor we use later */
1478 #if defined(__WXX11__) || defined(__WXGTK__) || defined(__WXOSX__)
1479 
1480 #ifdef __WXOSX__
1481        /* LSB (0x01) is leftmost. First byte is top row. 1 is black/visible*/
1482        char cursor_bits[] = {0x00, 0x0e, 0x0e, 0x0e, 0x00};
1483        char mask_bits[]   = {0x1f, 0x1f, 0x1f, 0x1f, 0x1f};
1484 #else
1485        char cursor_bits[] = {0xe0, 0xee, 0xee, 0xee, 0xe0};
1486        char mask_bits[]   = {0xe0, 0xe0, 0xe0, 0xe0, 0xe0};
1487 #endif
1488 
1489        wxBitmap bmp = wxBitmap(cursor_bits, 8, 5);
1490        bmp.SetMask(new wxMask(wxBitmap(mask_bits, 8, 5)));
1491 
1492        wxImage img = bmp.ConvertToImage();
1493        img.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, _T("2"));
1494        img.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, _T("2"));
1495 
1496        m_dot_cursor = new wxCursor(img);
1497 #endif
1498 }
1499 
~LisaWin(void)1500 LisaWin::~LisaWin(void)
1501 {
1502 #if defined(__WXX11__) || defined(__WXGTK__) || defined(__WXOSX__)
1503     delete m_dot_cursor;
1504 #endif
1505 }
1506 
1507 
OnVideoAntiAliased(wxCommandEvent & WXUNUSED (event))1508 void LisaEmFrame::OnVideoAntiAliased(wxCommandEvent& WXUNUSED(event))
1509 {
1510     if (screensizex<IWINSIZEX || screensizey<IWINSIZEY)
1511     {
1512         wxString msg;
1513         msg.Printf(_T("Your display is only (%d,%d).  This mode needs at least (%d,%d), will shut off skins."),
1514                    screensizex,screensizey,  IWINSIZEX,IWINSIZEY);
1515         wxMessageBox(msg,_T("The display is too small"));
1516         turn_skins_off();
1517 
1518         if (screensizey<IWINSIZEY) {my_lisawin->SetVideoMode(2); return;}  // even still too small, go raw bits mode.
1519     }
1520     my_lisawin->SetVideoMode(0);
1521 }
1522 
1523 
OnVideoAAGray(wxCommandEvent & WXUNUSED (event))1524 void LisaEmFrame::OnVideoAAGray(wxCommandEvent& WXUNUSED(event))
1525 {
1526 
1527     if (screensizex<IWINSIZEX || screensizey<IWINSIZEY)
1528     {
1529         wxString msg;
1530 		msg.Printf(_T("Your display is only (%d,%d).  This mode needs at least (%d,%d), will shut off skins."),
1531                    screensizex,screensizey,  IWINSIZEX,IWINSIZEY);
1532         wxMessageBox(msg,wxT("The display is too small"));
1533         turn_skins_off();
1534         if (screensizey<IWINSIZEY) {my_lisawin->SetVideoMode(2); return;}
1535     }
1536 
1537     my_lisawin->SetVideoMode(4);
1538 }
1539 //void LisaEmFrame::OnVideoScaled(wxCommandEvent& WXUNUSED(event))          {my_lisawin->SetVideoMode(5);}
OnVideoSingleY(wxCommandEvent & WXUNUSED (event))1540 void LisaEmFrame::OnVideoSingleY(wxCommandEvent& WXUNUSED(event))           {my_lisawin->SetVideoMode(2);}
1541 
1542 
OnVideoDoubleY(wxCommandEvent & WXUNUSED (event))1543 void LisaEmFrame::OnVideoDoubleY(wxCommandEvent& WXUNUSED(event))
1544 {
1545 
1546     if (screensizex<720+40 || screensizey<364*2+50)
1547     {
1548      wxString msg;
1549 		msg.Printf(_T("Your display is only (%d,%d).  This mode needs at least (%d,%d)."),
1550                 screensizex,screensizey,  720+40,364*2+50 );
1551         wxMessageBox(msg,wxT("The display is too small"));
1552 
1553      // oops!  The display size changed on us since the last time. i.e. notebook with small screen
1554      // previously connected to large monitor, now on native LCD
1555      if (lisa_ui_video_mode==1 || lisa_ui_video_mode==3)
1556         {
1557           my_lisawin->SetVideoMode(2); turn_skins_off();
1558         }
1559 
1560      return;
1561     } /// display too small ///////////////////////////////////////////////////////////////
1562 
1563 
1564     if (skins_on)
1565     {
1566      if (yesnomessagebox("This mode doesn't work with the Lisa Skin.  Shut off the skin?",
1567                          "Remove Skin?")==0) return;
1568     }
1569     my_lisawin->SetVideoMode(1);
1570     turn_skins_off();
1571 }
1572 
1573 
OnVideo2X3Y(wxCommandEvent & WXUNUSED (event))1574 void LisaEmFrame::OnVideo2X3Y(wxCommandEvent& WXUNUSED(event))
1575 {
1576     if (screensizex<720*2+40 ||screensizey<364*3+100)
1577     {
1578      wxString msg;
1579      msg.Printf(_T("Your display is only (%d,%d).  This mode needs at least (%d,%d)."),
1580                 screensizex,screensizey,  720*2+40,364*3+100 );
1581         wxMessageBox(msg,wxT("The display is too small"));
1582 
1583      // oops!  The display size changed on us since the last time. i.e. notebook with small screen
1584      // previously connected to large monitor, now on native LCD
1585      if (lisa_ui_video_mode==1 || lisa_ui_video_mode==3)
1586         {
1587           my_lisawin->SetVideoMode(2);
1588           turn_skins_off();
1589         }
1590 
1591 
1592      return;
1593     }
1594 
1595     if (skins_on)
1596     {
1597      if (yesnomessagebox("This mode doesn't work with the Lisa Skin.  Shut off the skin?",
1598                          "Remove Skin?")==0) return;
1599     }
1600 
1601     my_lisawin->SetVideoMode(3);
1602     turn_skins_off();
1603 }
1604 
1605 
1606 
OnSkinsOn(wxCommandEvent & WXUNUSED (event))1607 void LisaEmFrame::OnSkinsOn(wxCommandEvent& WXUNUSED(event))
1608 {
1609  if (lisa_ui_video_mode==1 || lisa_ui_video_mode==3)
1610  {
1611    if (yesnomessagebox("The current display mode doesn't work with the Lisa Skin. Change modes?",
1612                        "Change Display Mode?")==0) return;
1613 
1614     setvideomode(0);
1615   }
1616 
1617   skins_on_next_run=1;
1618   skins_on=1;
1619   turn_skins_on();
1620 }
1621 
1622 
OnSkinsOff(wxCommandEvent & WXUNUSED (event))1623 void LisaEmFrame::OnSkinsOff(wxCommandEvent& WXUNUSED(event))
1624 {
1625  skins_on_next_run=0;
1626  skins_on=0;
1627  turn_skins_off();
1628 }
1629 
OnRefresh60Hz(wxCommandEvent & WXUNUSED (event))1630 void LisaEmFrame::OnRefresh60Hz(wxCommandEvent& WXUNUSED(event)) {hostrefresh=1000/60; refresh_rate=1*REFRESHRATE; refresh_rate_used=refresh_rate;save_global_prefs();}
OnRefresh20Hz(wxCommandEvent & WXUNUSED (event))1631 void LisaEmFrame::OnRefresh20Hz(wxCommandEvent& WXUNUSED(event)) {hostrefresh=1000/20; refresh_rate=3*REFRESHRATE; refresh_rate_used=refresh_rate;save_global_prefs();}
OnRefresh12Hz(wxCommandEvent & WXUNUSED (event))1632 void LisaEmFrame::OnRefresh12Hz(wxCommandEvent& WXUNUSED(event)) {hostrefresh=1000/12; refresh_rate=5*REFRESHRATE; refresh_rate_used=refresh_rate;save_global_prefs();}
OnRefresh8Hz(wxCommandEvent & WXUNUSED (event))1633 void LisaEmFrame::OnRefresh8Hz( wxCommandEvent& WXUNUSED(event)) {hostrefresh=1000/ 8; refresh_rate=7*REFRESHRATE; refresh_rate_used=refresh_rate;save_global_prefs();}
OnRefresh4Hz(wxCommandEvent & WXUNUSED (event))1634 void LisaEmFrame::OnRefresh4Hz( wxCommandEvent& WXUNUSED(event)) {hostrefresh=1000/ 4; refresh_rate=9*REFRESHRATE; refresh_rate_used=refresh_rate;save_global_prefs();}
1635 
OnHideHostMouse(wxCommandEvent & WXUNUSED (event))1636 void LisaEmFrame::OnHideHostMouse(wxCommandEvent& WXUNUSED(event)) {hide_host_mouse=!hide_host_mouse; save_global_prefs();}
1637 
1638 
1639 
get_wx_millis(void)1640 extern "C" long get_wx_millis(void)
1641 {
1642  return my_lisaframe->runtime.Time();
1643 }
1644 
1645 
1646 
1647 
save_global_prefs(void)1648 void save_global_prefs(void)
1649 {
1650   int x,y;
1651 
1652   if (!myConfig)     return;                                 // not initialized yet
1653   if (!DisplayMenu)  return;
1654   if (!my_lisaframe) return;
1655   if (!fileMenu)     return;
1656 
1657   myConfig->Write(_T("/soundeffects"),sound_effects_on);
1658   myConfig->Write(_T("/displayskins"),skins_on_next_run);
1659   myConfig->Write(_T("/displaymode"), (long)lisa_ui_video_mode);
1660   myConfig->Write(_T("/asciikeyboard"), (long)asciikeyboard);
1661   myConfig->Write(_T("/lisaconfigfile"),myconfigfile);
1662   myConfig->Write(_T("/throttle"),(long)my_lisaframe->throttle);
1663 
1664   myConfig->Write(_T("/emutime"),(long)emulation_time);
1665   myConfig->Write(_T("/emutick"),(long)emulation_tick);
1666 
1667 
1668 
1669   myConfig->Write(_T("/refreshrate"),(long)refresh_rate);
1670   myConfig->Write(_T("/hidehostmouse"),(long)hide_host_mouse);
1671 
1672   my_lisawin->GetClientSize(&x,&y);
1673   myConfig->Write(_T("/lisawin/sizey"),(long)y-my_lisawin->dwy);
1674   myConfig->Write(_T("/lisawin/sizex"),(long)x-my_lisawin->dwx);
1675   my_lisaframe->GetClientSize(&x,&y);
1676   myConfig->Write(_T("/lisaframe/sizey"),(long)y-my_lisaframe->dwy);
1677   myConfig->Write(_T("/lisaframe/sizex"),(long)x-my_lisaframe->dwx);
1678 
1679 
1680   myConfig->Flush();
1681 
1682 
1683 
1684   DisplayMenu->Check(ID_VID_AA    ,lisa_ui_video_mode==0);  DisplayMenu->Enable(ID_VID_AA    ,lisa_ui_video_mode!=0x3a);
1685   DisplayMenu->Check(ID_VID_AAG   ,lisa_ui_video_mode==4);  DisplayMenu->Enable(ID_VID_AAG   ,lisa_ui_video_mode!=0x3a);
1686 //DisplayMenu->Check(ID_VID_SCALED,lisa_ui_video_mode==5);  DisplayMenu->Enable(ID_VID_SCALED,lisa_ui_video_mode!=0x3a);
1687   DisplayMenu->Check(ID_VID_DY    ,lisa_ui_video_mode==1);  DisplayMenu->Enable(ID_VID_DY    ,lisa_ui_video_mode!=0x3a);
1688   DisplayMenu->Check(ID_VID_SY    ,lisa_ui_video_mode==2);  DisplayMenu->Enable(ID_VID_SY    ,lisa_ui_video_mode!=0x3a);
1689   DisplayMenu->Check(ID_VID_2X3Y  ,lisa_ui_video_mode==3);  DisplayMenu->Enable(ID_VID_2X3Y  ,lisa_ui_video_mode!=0x3a);
1690 
1691   DisplayMenu->Check(ID_VID_SKINS_ON, !!skins_on);
1692   DisplayMenu->Check(ID_VID_SKINS_OFF, !skins_on);
1693 
1694   if ( refresh_rate!=9*REFRESHRATE  && refresh_rate!=7*REFRESHRATE  &&
1695        refresh_rate!=5*REFRESHRATE  && refresh_rate!=3*REFRESHRATE  &&
1696        refresh_rate!=  REFRESHRATE                                    ) refresh_rate =  REFRESHRATE;
1697 
1698   // reinstated as per request by Kallikak
1699   my_lisaframe->hostrefresh=1000/60;
1700   DisplayMenu->Check(ID_REFRESH_4Hz, refresh_rate==9*REFRESHRATE);  if (refresh_rate==9*REFRESHRATE) my_lisaframe->hostrefresh=1000/ 4;
1701   DisplayMenu->Check(ID_REFRESH_8Hz, refresh_rate==7*REFRESHRATE);  if (refresh_rate==7*REFRESHRATE) my_lisaframe->hostrefresh=1000/ 8;
1702   DisplayMenu->Check(ID_REFRESH_12Hz,refresh_rate==5*REFRESHRATE);  if (refresh_rate==7*REFRESHRATE) my_lisaframe->hostrefresh=1000/12;
1703   DisplayMenu->Check(ID_REFRESH_20Hz,refresh_rate==3*REFRESHRATE);  if (refresh_rate==7*REFRESHRATE) my_lisaframe->hostrefresh=1000/20;
1704   DisplayMenu->Check(ID_REFRESH_60Hz,refresh_rate==1*REFRESHRATE);  if (refresh_rate==7*REFRESHRATE) my_lisaframe->hostrefresh=1000/60;
1705 
1706 #ifdef DEBUG
1707 #ifdef TRACE
1708   fileMenu->Check(ID_DEBUG,!!debug_log_enabled);
1709 #endif
1710 #endif
1711 
1712   DisplayMenu->Check(ID_HIDE_HOST_MOUSE,!!hide_host_mouse);
1713 
1714   keyMenu->Check(ID_ASCIIKB,  asciikeyboard== 1);
1715   keyMenu->Check(ID_RAWKB,    asciikeyboard== 0);
1716   keyMenu->Check(ID_RAWKBBUF, asciikeyboard==-1);
1717 
1718   updateThrottleMenus(my_lisaframe->throttle);
1719 }
1720 
1721 
SetStatusBarText(wxString & msg)1722 void LisaEmFrame::SetStatusBarText(wxString &msg) {SetStatusText(msg,0);}
1723 
1724 DECLARE_APP(LisaEmApp)           // Implements LisaEmApp& GetApp()
IMPLEMENT_APP(LisaEmApp)1725 IMPLEMENT_APP(LisaEmApp)         // Give wxWidgets the means to create a LisaEmApp object
1726 
1727 
1728 // Initialize the application
1729 bool LisaEmApp::OnInit()
1730 {
1731     wxString argv1;
1732     wxString Ext;
1733 
1734 	wxString defaultconfig = wxGetHomeDir();
1735     #ifdef __UNIX__
1736     if (defaultconfig.Last() != wxT('/') )  defaultconfig  <<wxT("/lisaem.conf");
1737     #else
1738     if (defaultconfig.Last() != wxT('\\') )  defaultconfig  <<wxT("\\lisaem.conf");
1739     #endif
1740 
1741     myConfig = wxConfig::Get();         // this one is the global configuration for the app.
1742                                         // get the path to the last opened Lisaconfig and load that.
1743 
1744     myconfigfile=myConfig->Read(_T("/lisaconfigfile"),defaultconfig);
1745 
1746     // override config file on startup if passed a parameter.
1747     if (argc>1)
1748     {
1749       argv1.Printf(_T("%s"),argv[1]);
1750       const char *ext=strstr(
1751                   (const char *)(argv1.fn_str()),
1752                   (const char *)(".lisaem"));
1753 
1754       if (ext!=NULL && strlen(ext)==7)  // ensure the proper extension is contained.
1755          {
1756             argv1.Printf(_T("%s"),argv[1]);
1757             if (wxFile::Exists(argv1) ) myconfigfile=argv1;
1758          }
1759     }
1760 
1761 
1762     pConfig=new wxFileConfig(_T("LisaEm"),
1763                              _T("sunder.NET"),
1764                              (myconfigfile),     //local
1765                              (myconfigfile),     //global
1766                              wxCONFIG_USE_LOCAL_FILE,
1767                              wxConvAuto() );   // or wxConvUTF8
1768 
1769     // this is a global setting  - must be right before the LisaFrame!
1770     skins_on          =(int)myConfig->Read(_T("/displayskins"),(long)1);
1771     skins_on_next_run=skins_on;
1772 
1773     // Create the main application window
1774     my_lisaframe=new LisaEmFrame(wxT("LisaEm"));
1775 
1776     refresh_rate      =(long)myConfig->Read(_T("/refreshrate"),(long)REFRESHRATE);
1777     hide_host_mouse   =(int) myConfig->Read(_T("/hidehostmouse"),(long)0);
1778     refresh_rate_used=refresh_rate;
1779     sound_effects_on  =(int)myConfig->Read(_T("/soundeffects"),(long)1);
1780     lisa_ui_video_mode=(int)myConfig->Read(_T("/displaymode"), (long)0);
1781     asciikeyboard     =(int)myConfig->Read(_T("/asciikeyboard"),(long)1);
1782     my_lisaframe->throttle=(float)(myConfig->Read(_T("/throttle"),(long)5));
1783 
1784     emulation_time=(long)myConfig->Read(_T("/emutime"),(long)100);
1785     emulation_tick=(long)myConfig->Read(_T("/emutick"),(long)75);
1786 
1787 
1788 //    ALERT_LOG(0,"Initial system start up Throttle:%f clkfactor:%f",
1789 //              my_lisaframe->throttle,my_lisaframe->clockfactor);
1790 
1791     save_global_prefs();
1792 
1793     DEBUG_LOG(0,"CreatingLisaconfig()");
1794     my_lisaconfig = new LisaConfig();
1795     DEBUG_LOG(0,"Created Lisaconfig()");
1796 
1797     pConfig->SetRecordDefaults();
1798 
1799     DEBUG_LOG(0,"Loading Config");
1800     my_lisaconfig->Load(pConfig, floppy_ram);// load it in
1801     DEBUG_LOG(0,"Saving Config");
1802     my_lisaconfig->Save(pConfig, floppy_ram);// save it so defaults are created
1803 
1804 
1805 
1806     my_lisaframe->running=emulation_off;     // CPU isn't yet turned on
1807 
1808 
1809     SetVendorName(_T("sunder.NET"));
1810     SetAppName(_T("LisaEm"));
1811 	my_lisawin->repaintall = REPAINT_INVALID_WINDOW;
1812     my_lisaframe->Show(true);                // Light it up
1813 	my_lisawin->repaintall = REPAINT_INVALID_WINDOW;
1814 
1815     wxStandardPathsBase& stdp = wxStandardPaths::Get();
1816 	wxString sndfile;
1817 	wxString rscDir = stdp.GetResourcesDir() + wxFileName::GetPathSeparator(wxPATH_NATIVE);
1818 
1819     // stare not upon the insanity that predated this code, for it was written by drunkards! (*Burp*)
1820     sndfile=rscDir + _T("floppy_eject.wav");           my_floppy_eject  =       new wxSound(sndfile);
1821     sndfile=rscDir + _T("floppy_insert_sound.wav");    my_floppy_insert =       new wxSound(sndfile);
1822     sndfile=rscDir + _T("floppy_motor1.wav");          my_floppy_motor1 =       new wxSound(sndfile);
1823     sndfile=rscDir + _T("floppy_motor2.wav");          my_floppy_motor2 =       new wxSound(sndfile);
1824     sndfile=rscDir + _T("lisa_power_switch01.wav");    my_lisa_power_switch01 = new wxSound(sndfile);
1825     sndfile=rscDir + _T("lisa_power_switch02.wav");    my_lisa_power_switch02 = new wxSound(sndfile);
1826     sndfile=rscDir + _T("poweroffclk.wav");            my_poweroffclk =         new wxSound(sndfile);
1827 
1828 	my_lisaframe->UpdateProfileMenu();
1829 
1830     black();
1831 
1832     return true;
1833 }
1834 
1835 
1836 
1837 
1838 
1839 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1840 //
1841 // Keyboard Scancodes - these are valid for all keyboards, except that 42 is not on the US keyboard
1842 //                      and 48 is not on the EU keyboard.
1843 //
1844 //                               0    1    2    3    4    5    6    7    8    9   10   11  12   13  14
1845 uint8 kbcodes[5][15]=      { {0x68,0x74,0x71,0x72,0x73,0x64,0x61,0x62,0x63,0x50,0x51,0x40,0x41,0x45, 0 },
1846                              {0x78,0x75,0x77,0x60,0x65,0x66,0x67,0x52,0x53,0x5f,0x44,0x56,0x57,0x42, 0 },
1847                              {0x7d,0x70,0x76,0x7b,0x69,0x6a,0x6b,0x54,0x55,0x59,0x5a,0x5b,0x42,0x48, 0 },
1848                              {0x7e,0x43,0x79,0x7a,0x6d,0x6c,0x6e,0x6f,0x58,0x5d,0x5e,0x4c,0x7e,   0, 0 },
1849                              {0x7c,0x7f,0x5c,0x46,0x4e,   0,   0,   0,   0,   0,   0,   0,   0,   0, 0 } };
1850 //
1851 //                              0    1    2    3   4
1852 uint8 kbcodesn[ 5][5]=     { {0x20,0x21,0x22,0x23, 0},
1853                              {0x24,0x25,0x26,0x27, 0},
1854                              {0x28,0x29,0x2a,0x2b, 0},
1855                              {0x4d,0x2d,0x2e,0x2f, 0},
1856                              {0x49,0x2c,   0,   0, 0}                                                    };
1857 //
1858 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1859 //
1860 // Keyboard Legends - need to build these for the other languages /////////////////////////////////////////////////
1861 //                  - also need to build 3x more (shifted, option, option+shift)
1862 //
1863 //                             0        1   2   3   4   5   6   7   8   9   10 11  12  13          14
1864 char *kb_us_r1_txt[5][15]= { {"`",     "1","2","3","4","5","6","7","8","9","0","-","=","BACKSPACE","" },
1865                              {"TAB",   "q","w","e","r","t","y","u","i","o","p","[","]","\\"       ,"" },
1866                              {"CAPS",  "a","s","d","f","g","h","j","k","l",";","'","" ,"RETURN"   ,"" },
1867                              {"SHIFT", "", "z","x","c","v","b","n","m",",",".","/","SHIFT",""     ,"" },
1868                              {"OPT","CMD","SPACE","ENTER","OPT","","","","","","","","",""        ,"" }  };
1869 //
1870 char *kb_us_n1_txt[ 5][5]= { {"CLR","-","+","*"    ,""  },
1871                              {  "7","8","9","/"    ,""  },
1872                              {  "4","5","6",","    ,""  },
1873                              {  "1","2","3","ENTER",""  },
1874                              {  "0",".","" ,""     ,""  }                                                };
1875 //
1876 //
1877 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1878 
1879 //borrowed from wxWidgets example code:  keyboard.cpp by  Vadim Zeitlin
LogKeyEvent(const wxChar * WXUNUSED (name),wxKeyEvent & event,int keydir)1880 void LisaWin::LogKeyEvent(const wxChar* WXUNUSED(name), wxKeyEvent& event, int keydir)
1881 {
1882     wxString key;
1883     long keycode = event.GetKeyCode();
1884     int lisakey=0;
1885 
1886     int forcelisakey=0;
1887 
1888     // on linux for some reason I get keycode=-1 for ALT!!!
1889     #ifdef __WXX11__
1890     if (keycode==-1) keycode=WXK_ALT;
1891     #endif
1892 
1893     //ALERT_LOG(0,"Received %08x keycode on event %d",keycode,keydir);
1894     switch ( keycode )
1895     {
1896 //
1897 // need to implement variations of these for the other keyboard languages too.
1898 // also should get rid of this and replace it with some sort of table/array instead.
1899 //
1900 
1901         case WXK_LEFT:
1902         case WXK_NUMPAD_LEFT:        lisakey=KEYCODE_CURSORL;  forcelisakey=1;       break;
1903 
1904         case WXK_UP :
1905         case WXK_NUMPAD_UP:          lisakey=KEYCODE_CURSORU;  forcelisakey=1;       break;
1906 
1907         case WXK_RIGHT :
1908         case WXK_NUMPAD_RIGHT:       lisakey=KEYCODE_CURSORR;  forcelisakey=1;       break;
1909 
1910         case WXK_DOWN:
1911         case WXK_NUMPAD_DOWN :       lisakey=KEYCODE_CURSORD;  forcelisakey=1;       break;
1912 
1913 
1914         case WXK_NUMPAD_INSERT:      lisakey=KEYCODE_LENTER;          break;
1915         case WXK_NUMPAD_DELETE:      lisakey=KEYCODE_BACKSPACE;       break;
1916 
1917       //case WXK_NUMPAD_EQUAL:       lisakey=KEYCODE_EQUAL;           break;
1918         case WXK_NUMPAD_MULTIPLY:    lisakey=KEYCODE_STAR_NUM;        break;
1919         case WXK_NUMPAD_ADD:         lisakey=KEYCODE_PLUS_NUM;        break;
1920         case WXK_NUMPAD_SEPARATOR:
1921         case WXK_NUMPAD_SUBTRACT:    lisakey=KEYCODE_MINUS_NUM;       break;
1922         case WXK_NUMPAD_DECIMAL:     lisakey=KEYCODE_DOTNUM;          break;
1923         case WXK_NUMPAD_DIVIDE:      lisakey=KEYCODE_FSLASH;          break;
1924 
1925         case WXK_NUMPAD_ENTER:       lisakey=KEYCODE_ENTERNUM;        break;
1926         case WXK_NUMLOCK:            lisakey=KEYCODE_CLEAR;           break;
1927 
1928         case WXK_NUMPAD0:            lisakey=KEYCODE_0NUM;            break;
1929         case WXK_NUMPAD1:            lisakey=KEYCODE_1NUM;            break;
1930         case WXK_NUMPAD2:            lisakey=KEYCODE_2NUM;            break;
1931         case WXK_NUMPAD3:            lisakey=KEYCODE_3NUM;            break;
1932         case WXK_NUMPAD4:            lisakey=KEYCODE_4NUM;            break;
1933         case WXK_NUMPAD5:            lisakey=KEYCODE_5NUM;            break;
1934         case WXK_NUMPAD6:            lisakey=KEYCODE_6NUM;            break;
1935         case WXK_NUMPAD7:            lisakey=KEYCODE_7NUM;            break;
1936         case WXK_NUMPAD8:            lisakey=KEYCODE_8NUM;            break;
1937         case WXK_NUMPAD9:            lisakey=KEYCODE_9NUM;            break;
1938 
1939         case WXK_BACK:               lisakey=KEYCODE_BACKSPACE;       break;
1940         case WXK_TAB:                lisakey=KEYCODE_TAB;             break;
1941         case WXK_RETURN:             lisakey=KEYCODE_RETURN;          break;
1942         case WXK_ESCAPE:             lisakey=KEYCODE_CLEAR;           break;
1943         case WXK_SPACE:              lisakey=KEYCODE_SPACE;           break;
1944         case WXK_DELETE:             lisakey=KEYCODE_BACKSPACE;       break;
1945 
1946 
1947 
1948         case 'a' :                   lisakey=KEYCODE_A;               break;
1949         case 'b' :                   lisakey=KEYCODE_B;               break;
1950         case 'c' :                   lisakey=KEYCODE_C;               break;
1951         case 'd' :                   lisakey=KEYCODE_D;               break;
1952         case 'e' :                   lisakey=KEYCODE_E;               break;
1953         case 'f' :                   lisakey=KEYCODE_F;               break;
1954         case 'g' :                   lisakey=KEYCODE_G;               break;
1955         case 'h' :                   lisakey=KEYCODE_H;               break;
1956         case 'i' :                   lisakey=KEYCODE_I;               break;
1957         case 'j' :                   lisakey=KEYCODE_J;               break;
1958         case 'k' :                   lisakey=KEYCODE_K;               break;
1959         case 'l' :                   lisakey=KEYCODE_L;               break;
1960         case 'm' :                   lisakey=KEYCODE_M;               break;
1961         case 'n' :                   lisakey=KEYCODE_N;               break;
1962         case 'o' :                   lisakey=KEYCODE_O;               break;
1963         case 'p' :                   lisakey=KEYCODE_P;               break;
1964         case 'q' :                   lisakey=KEYCODE_Q;               break;
1965         case 'r' :                   lisakey=KEYCODE_R;               break;
1966         case 's' :                   lisakey=KEYCODE_S;               break;
1967         case 't' :                   lisakey=KEYCODE_T;               break;
1968         case 'u' :                   lisakey=KEYCODE_U;               break;
1969         case 'v' :                   lisakey=KEYCODE_V;               break;
1970         case 'w' :                   lisakey=KEYCODE_W;               break;
1971         case 'x' :                   lisakey=KEYCODE_X;               break;
1972         case 'y' :                   lisakey=KEYCODE_Y;               break;
1973         case 'z' :                   lisakey=KEYCODE_Z;               break;
1974 
1975         case 'A' :                   lisakey=KEYCODE_A;               break;
1976         case 'B' :                   lisakey=KEYCODE_B;               break;
1977         case 'C' :                   lisakey=KEYCODE_C;               break;
1978         case 'D' :                   lisakey=KEYCODE_D;               break;
1979         case 'E' :                   lisakey=KEYCODE_E;               break;
1980         case 'F' :                   lisakey=KEYCODE_F;               break;
1981         case 'G' :                   lisakey=KEYCODE_G;               break;
1982         case 'H' :                   lisakey=KEYCODE_H;               break;
1983         case 'I' :                   lisakey=KEYCODE_I;               break;
1984         case 'J' :                   lisakey=KEYCODE_J;               break;
1985         case 'K' :                   lisakey=KEYCODE_K;               break;
1986         case 'L' :                   lisakey=KEYCODE_L;               break;
1987         case 'M' :                   lisakey=KEYCODE_M;               break;
1988         case 'N' :                   lisakey=KEYCODE_N;               break;
1989         case 'O' :                   lisakey=KEYCODE_O;               break;
1990         case 'P' :                   lisakey=KEYCODE_P;               break;
1991         case 'Q' :                   lisakey=KEYCODE_Q;               break;
1992         case 'R' :                   lisakey=KEYCODE_R;               break;
1993         case 'S' :                   lisakey=KEYCODE_S;               break;
1994         case 'T' :                   lisakey=KEYCODE_T;               break;
1995         case 'U' :                   lisakey=KEYCODE_U;               break;
1996         case 'V' :                   lisakey=KEYCODE_V;               break;
1997         case 'W' :                   lisakey=KEYCODE_W;               break;
1998         case 'X' :                   lisakey=KEYCODE_X;               break;
1999         case 'Y' :                   lisakey=KEYCODE_Y;               break;
2000         case 'Z' :                   lisakey=KEYCODE_Z;               break;
2001 
2002         case '0' :                   lisakey=KEYCODE_0;               break;
2003         case '1' :                   lisakey=KEYCODE_1;               break;
2004         case '2' :                   lisakey=KEYCODE_2;               break;
2005         case '3' :                   lisakey=KEYCODE_3;               break;
2006         case '4' :                   lisakey=KEYCODE_4;               break;
2007         case '5' :                   lisakey=KEYCODE_5;               break;
2008         case '6' :                   lisakey=KEYCODE_6;               break;
2009         case '7' :                   lisakey=KEYCODE_7;               break;
2010         case '8' :                   lisakey=KEYCODE_8;               break;
2011         case '9' :                   lisakey=KEYCODE_9;               break;
2012 
2013 
2014         case        '~':
2015         case        '`':             lisakey=KEYCODE_TILDE;           break;
2016 
2017         case        '_':
2018         case        '-':             lisakey=KEYCODE_MINUS;           break;
2019 
2020         case        '+':
2021         case        '=':             lisakey=KEYCODE_PLUS;            break;
2022 
2023         case        '{':
2024         case        '[':             lisakey=KEYCODE_OBRAK;           break;
2025 
2026         case        '}':
2027         case        ']':             lisakey=KEYCODE_CBRAK;           break;
2028 
2029 
2030         case        '|':
2031         case        '\\':            lisakey=KEYCODE_BSLASH;          break;
2032 
2033         case        ':':
2034         case        ';':             lisakey=KEYCODE_COLON;           break;
2035 
2036         case        '"':
2037         case        '\'':            lisakey=KEYCODE_QUOTE;           break;
2038 
2039         case        '<':
2040         case        ',':             lisakey=KEYCODE_COMMA;           break;
2041 
2042         case        '>':
2043         case        '.':             lisakey=KEYCODE_DOT;             break;
2044 
2045         case        '?':
2046         case        '/':             lisakey=KEYCODE_FSLASHQ;         break;
2047 
2048 
2049         case WXK_SHIFT:              lisakey=KEYCODE_SHIFT;           break;
2050         case WXK_ALT:                lisakey=KEYCODE_COMMAND;         break;
2051         case WXK_CONTROL:            lisakey=KEYCODE_LOPTION;         break;
2052     }
2053 
2054 int i;
2055 
2056 switch (asciikeyboard)
2057 {
2058  case 1:
2059 
2060                  if (keydir==2 && lastkeystroke==-1)
2061                     {
2062                         if (forcelisakey)   {
2063                                               if (forcelisakey & 8) send_cops_keycode(KEYCODE_COMMAND|KEY_DOWN);
2064                                               if (forcelisakey & 4) send_cops_keycode(KEYCODE_SHIFT  |KEY_DOWN);
2065                                               if (forcelisakey & 2) send_cops_keycode(KEYCODE_OPTION |KEY_DOWN);
2066                                                                     send_cops_keycode(lisakey        |KEY_DOWN);
2067                                                                     send_cops_keycode(lisakey        |KEY_UP  );
2068                                               if (forcelisakey & 2) send_cops_keycode(KEYCODE_OPTION |KEY_UP  );
2069                                               if (forcelisakey & 4) send_cops_keycode(KEYCODE_SHIFT  |KEY_UP  );
2070                                               if (forcelisakey & 8) send_cops_keycode(KEYCODE_COMMAND|KEY_UP  );
2071                                             }
2072                         else
2073                                             keystroke_cops(keycode);
2074                     }
2075                  lastkeystroke=-1;
2076                  return;
2077 
2078 
2079 case 0 :         //     old raw unbuffered way - causes repetitions!
2080                  if (keydir==-1)                lisakey |=KEY_DOWN;
2081                  if (lisakey & 0x7f)            {//ALERT_LOG(0,"Sending rawkeycode %02x",lisakey);
2082                                                  send_cops_keycode(lisakey);}
2083                  lastkeystroke=-1;
2084                  return;
2085 
2086 case -1 :
2087                  // raw keycodes are a lot more complicated because of timing, the Lisa will almost always
2088                  // repeat keys when they are unwanted.  This code attempts to buffer the codes and later
2089                  // on key-up events, let go of them.  It attempts to handle things such as holding shift,
2090                  // then typing A,B,C, and will send shift-down,a-down,a-up,shift-up,shift-down,b-down, etc...
2091                  //
2092                  // in some ways it's an attempt to "cook" raw keycodes, but it doesn't use ASCII translation.
2093 
2094 
2095 
2096                  // handle repeating keys by watching the host repeat
2097                  if (keydir==-1 && rawidx>0 && rawcodes[rawidx-1]==lisakey) keydir=1;
2098 
2099 
2100                  // key down
2101                  if (keydir==-1)                     // key down, don't send anything, just buffer.
2102                  {
2103                     // see if wxWidgets will send more than one keydown, if it does we have a way!
2104                     if (rawidx>=127) return;         // avoid overflow
2105                     if (rawidx) for ( i=0; i<rawidx; i++)
2106                                      if (lisakey==rawcodes[i])
2107                                         {
2108                                          //ALERT_LOG(0,"Suppressing duplicate keydown:%d",lisakey);
2109                                          return;
2110                                         }
2111 
2112 
2113                     rawcodes[rawidx]=lisakey;
2114                     //ALERT_LOG(0,"Queueing rawcodes[%d]=%02x ",rawidx,lisakey);
2115                     rawidx++;
2116                  }
2117 
2118 
2119 
2120 
2121 
2122                  // so this can handle shift-keydown-keyup-shift up, but won't handle any more than that.
2123                  // also handle shift-keydown-keyup-keydown-up-down-up-shift-up!
2124                  //
2125                  // also handle shiftdown,control-down,option-down-key-down-up,keydown-up, control-up, ...etc.
2126                  //
2127                  // so want to release all keys the first time any key is released, but don't flush the buffer until
2128                  // all keys are released!
2129                  //
2130                  // * also need to handle shift-down-adown-shift-up-a-up, etc.
2131                  //
2132                  // * remaining bug here is that this won't handle repeating keys.
2133 
2134                  if (keydir==1)                      // key released
2135                  {
2136                    int i,flag=0;
2137                    if (rawidx==0) {//ALERT_LOG(0,"Returning since rawdown=0");
2138                                    return;}           // nothing in the buffer
2139                    //static int lastkeyup;
2140 
2141                    //if (lisakey==lastkeyup) ALERT_LOG(0,"Multiple key up:%d",lisakey);
2142 
2143                    // prevent keydown syndrome. i.e. when typing there, if you type in like this:
2144                    // t-down, h-down, t-up, h-up, you get "tht" without this return.  Most people aren't
2145                    // aware that they're doing this, I certainly wasn't until just down because most kbd
2146                    // drivers compensate for this!
2147                    //if (lisakey!=rawcodes[rawidx-1]) return;  // this isn't right. *** want to ignore any keys up no longer in the buffer ***
2148 
2149                    if (lisakey!=rawcodes[rawidx-1] &&
2150                        lisakey!=KEYCODE_COMMAND    &&
2151                        lisakey!=KEYCODE_OPTION     &&
2152                        lisakey!=KEYCODE_SHIFT        )
2153                       for (i=0; i<rawidx; i++)
2154                       {
2155                           if (//rawcodes[i]!=lisakey &&
2156                               rawcodes[i]!=0                &&
2157                               rawcodes[i]!=KEYCODE_COMMAND  &&
2158                               rawcodes[i]!=KEYCODE_OPTION   &&
2159                               rawcodes[i]!=KEYCODE_SHIFT       )
2160                               { //ALERT_LOG(0,"all non-meta keys have not yet been released.");
2161                                 return;}
2162                       }
2163 
2164 
2165                    //--------------------------------------------------------------------------
2166                    // if there's nothing left in the buffer except for Apple,Option, and shift
2167                    // we don't have anything to send to the Lisa.  i.e. on final release of shift
2168                    // or option, or Apple key.
2169 
2170                    for (flag=0,i=0; i<rawidx && !flag; i++)
2171                    {
2172                        if (rawcodes[i]!=0                &&
2173                            rawcodes[i]!=KEYCODE_COMMAND  &&
2174                            rawcodes[i]!=KEYCODE_OPTION   &&
2175                            rawcodes[i]!=KEYCODE_SHIFT       ) flag=1;
2176                    }
2177 
2178                    // if the user let go of a modifier key, don't return anything, just remove it
2179                    if ( (lisakey==KEYCODE_COMMAND ||
2180                          lisakey==KEYCODE_OPTION  ||
2181                          lisakey==KEYCODE_SHIFT     ) )
2182                          {
2183                                for (i=0; i<rawidx && rawcodes[i]!=lisakey; i++);    //find modifier to delete.
2184                                if (i<rawidx-1) memmove(&rawcodes[i],&rawcodes[i+1],(128-i)*sizeof(int));
2185 
2186                                rawidx--;
2187 
2188                                // safety kludge - ensure that we let go of the modifiers so we don't leave the
2189                                // keyboard in a screwey state.
2190                                if (!rawidx) {send_cops_keycode(KEYCODE_COMMAND | KEY_UP);
2191                                              send_cops_keycode(KEYCODE_OPTION  | KEY_UP);
2192                                              send_cops_keycode(KEYCODE_SHIFT   | KEY_UP);
2193                                             }
2194 
2195                                  return;
2196                          }
2197                    //--------------------------------------------------------------------------
2198                    if (!flag) {//ALERT_LOG(0,"all left is shift/opt/cmd - returning");
2199 
2200                                // safety kludge - ensure that we let go of the modifiers so we don't leave the
2201                                // keyboard in a screwey state.
2202                                if (!rawidx) {send_cops_keycode(KEYCODE_COMMAND | KEY_UP);
2203                                              send_cops_keycode(KEYCODE_OPTION  | KEY_UP);
2204                                              send_cops_keycode(KEYCODE_SHIFT   | KEY_UP);
2205                                             }
2206                                return; }              // if all that's left are modifiers, return.
2207 
2208 
2209                    //ALERT_LOG(0,"\nlisakey Keyup:%d",lisakey);
2210                    for (i=0; i<rawidx; i++)         { //ALERT_LOG(0,"sending down[%d]=%d",i,rawcodes[i]);
2211                                                       if (rawcodes[i]!=0)
2212                                                        send_cops_keycode(rawcodes[i]|KEY_DOWN); }
2213 
2214                    for (i=rawidx-1; i>=0; i--)      { //ALERT_LOG(0,"sending up[%d]=%d",i,rawcodes[i]);
2215                                                       if (rawcodes[i]!=0)
2216                                                        send_cops_keycode(rawcodes[i]|KEY_UP);    }
2217 
2218 
2219                    //ALERT_LOG(0,"done\n");
2220 
2221 
2222                    // remove any keystrokes from the buffer we've just sent out other than the meta keys.
2223                    for (i=0; i<rawidx; i++)
2224                    {
2225                       if (KEYCODE_COMMAND!=rawcodes[i] &&
2226                           KEYCODE_OPTION !=rawcodes[i] &&
2227                           KEYCODE_SHIFT  !=rawcodes[i] &&
2228                                        0 !=rawcodes[i]    ) rawcodes[i]=0;
2229                    }
2230 
2231                    // if they're at the end, shrink the buffer - it's ok to leave holes, just don't want to.
2232                    while (rawidx>0 && rawcodes[rawidx-1]==0) rawidx--;
2233 
2234                    // safety kludge - ensure that we let go of the modifiers so we don't leave the
2235                    // keyboard in a screwey state.
2236                    if (!rawidx) {send_cops_keycode(KEYCODE_COMMAND | KEY_UP);
2237                                  send_cops_keycode(KEYCODE_OPTION  | KEY_UP);
2238                                  send_cops_keycode(KEYCODE_SHIFT   | KEY_UP);
2239                                 }
2240                    return;
2241 
2242 
2243 
2244                  }
2245         return;
2246 
2247 }
2248 
2249 
2250 }
2251 
2252 
OnKeyDown(wxKeyEvent & event)2253 void LisaWin::OnKeyDown(wxKeyEvent& event)
2254 {
2255 
2256         long keycode = event.GetKeyCode();
2257 
2258         //ALERT_LOG(0,"Key down:%x, shift:%x, alt:%x, control:%x", keycode,
2259         //          WXK_SHIFT,
2260         //          WXK_ALT,
2261         //          WXK_CONTROL);
2262 
2263         if (keycode==-1) keycode=WXK_ALT;
2264 
2265 
2266         if (
2267              keycode==WXK_LEFT ||                   // avoid cursor keys turning into ascii
2268              keycode==WXK_UP   ||
2269              keycode==WXK_RIGHT||
2270              keycode==WXK_DOWN ||
2271 
2272              keycode==WXK_NUMPAD_LEFT ||
2273              keycode==WXK_NUMPAD_UP   ||
2274              keycode==WXK_NUMPAD_RIGHT||
2275              keycode==WXK_NUMPAD_DOWN   )            {LogKeyEvent(_T("Key down"), event,-1);event.Skip(); return;}
2276 
2277 
2278     if (asciikeyboard==1) event.Skip(); else LogKeyEvent(_T("Key down"), event,-1);
2279 
2280 }
2281 
OnKeyUp(wxKeyEvent & event)2282 void LisaWin::OnKeyUp(wxKeyEvent& event)
2283 {
2284     //ALERT_LOG(0,"Key Up. Throttle:%f clk:%f",my_lisaframe->throttle,my_lisaframe->clockfactor);
2285 
2286 
2287         long keycode = event.GetKeyCode();
2288 
2289         if (
2290              keycode==WXK_LEFT ||                   // avoid cursor keys turning into ascii
2291              keycode==WXK_UP   ||
2292              keycode==WXK_RIGHT||
2293              keycode==WXK_DOWN ||
2294 
2295              keycode==WXK_NUMPAD_LEFT ||
2296              keycode==WXK_NUMPAD_UP   ||
2297              keycode==WXK_NUMPAD_RIGHT||
2298              keycode==WXK_NUMPAD_DOWN   )            {LogKeyEvent(_T("Key up"), event,1);event.Skip(); return;}
2299 
2300 
2301     if (asciikeyboard==1) event.Skip(); else LogKeyEvent(_T("Key up"), event,1);
2302 
2303     videoramdirty++;
2304 }
2305 
OnChar(wxKeyEvent & event)2306 void LisaWin::OnChar(wxKeyEvent& event)
2307 {
2308 
2309    long keycode = event.GetKeyCode();
2310    if (keycode==-1) keycode=WXK_ALT;
2311 
2312    if (
2313 
2314        keycode==WXK_SHIFT ||                    // avoid inserting extra ascii 1,2,4 on shift,alt,control down.
2315        keycode==WXK_ALT   ||
2316        keycode==WXK_CONTROL  ) return;
2317 
2318    wxString x; x.Printf(_T("keychar %c %08lx"),(char)keycode,keycode );
2319    my_lisaframe->SetStatusBarText(x);
2320    if (asciikeyboard==1)
2321       {
2322         LogKeyEvent(_T("Char"), event, 2);
2323         event.Skip(false); //else  LogKeyEvent(_T("Char"), event, 2);
2324       }
2325 }
2326 
2327 
2328 #define M8(x) (x>255 ? (255): (x))
2329 
ContrastChange(void)2330 void LisaWin::ContrastChange(void)
2331 {
2332   	  if ((contrast>>1)==lastcontrast)      return;
2333 
2334       lastcontrast=contrast>>1;
2335 
2336       int mc=0x88+( 0x7f^(contrast>>1)  );                // my contrast
2337 
2338       if (contrast<0xe0)
2339       {
2340         int step=(mc-brightness)/10;
2341   		/* white */ bright[0]=MIN(240,mc);
2342   		/* dark0 */ bright[1]=MIN(240,brightness+step*6);
2343   		/* dark1 */ bright[2]=bright[3]=MIN(240,brightness+step*5);
2344         /* black */ bright[4]=bright[5]=bright[6]=bright[7]=MIN(240,brightness);
2345 
2346         /* AAGray*/ bright[8] = bright[9] = bright[10]= bright[11]= bright[12]=
2347                     bright[13]= bright[14] =bright[15]=                  (mc+brightness)>>1;
2348 
2349      }
2350   else                                   // contrast is all black
2351       {
2352   		bright[0]=0;
2353   		bright[1]=0;
2354   		bright[2]=0;
2355   		bright[3]=0;
2356   		bright[4]=0;
2357   		bright[5]=0;
2358   		bright[6]=0;
2359   		bright[7]=0;
2360 
2361         bright[8] = bright[9] = bright[10]= bright[11]= bright[12]=bright[13] = bright[14] =bright[15]=0;
2362 
2363       }
2364 
2365       refresh_bytemap=0;        // we just refreshed the contrast table
2366       dirtyscreen=1;            // however, the screen bitmap is now dirty
2367       videoramdirty=32768;
2368 
2369   #ifndef __WXOSX__             // 2007.03.14 disabled for os x since it slows down shutdown a whole lot
2370       force_refresh();          // win32 still has contrast-trails. :-( 20070216
2371   #endif
2372 
2373 }
2374 
2375 
2376 
2377 // Repainters //////////////////////////////////////////////////////////////////////////////////////////
2378 
2379 
2380 
2381 
2382 ///////////////// SETRGB 16 bit AntiAliased MACRO //////////////////////////////////////////////////////
2383 //                                                                                                    //
2384 //  macro to fill in r,g,b values, does 16 pixels at a time, must be a macro because of the Z param   //
2385 //  and we want to get as much speed out of it as possible.                                           //
2386 //                                                                                                    //
2387 //  This would have been a 32 pixel macro if it were possible, however, since a single row is on the  //
2388 //  Lisa's display is either 90 bytes or 76 bytes, we can only evenly divide by 2 bytes (16 bits.)    //
2389 //                                                                                                    //
2390 //                                                                                                    //
2391 //  x,y are x,y coordinates on the bitmap.   They map to the Lisa's display, any other translation    //
2392 //  must be handled in Z, or via other variables.   x gets incremented for each pixel handled.        //
2393 //  x,y must be simple variables, and should not be expressions!                                      //
2394 //                                                                                                    //
2395 //  Z is a chunk of code to set r,g,b provided by the caller.  Z gets executed 16 times, once per     //
2396 //  pixel.  This is needed because we might be using SetRGB on images or rawbitmap accesss, or some   //
2397 //  other method in the future.   Z should be protected by enclosing it in curly braces when passing. //
2398 //  Z may use the uint8 d to actually set the darkness level for a pixel.                             //
2399 //                                                                                                    //
2400 //  Y is identical to Z except that it's code to call when there's no update.  i.e. ++p               //
2401 //                                                                                                    //
2402 //                                                                                                    //
2403 //  The following variables should be declared before calling this macro:                             //
2404 //                                                                                                    //
2405 //         int updated=0;	        // number of times we've made updates.                            //
2406 //                                  // can be used as a threshhold to decide how to redraw the image. //
2407 //         uint32 a1,a2,a3,xx;      // address above, below, for this value, horziontal byte offset   //
2408 //         uint16 vup,vdn,val;      // value above, below, this words read from addr @ a1,a2,a3       //
2409 //         uint16 high,medium,low;  // used for antialiasing. how many neighboring bits               //
2410 //         uint8 d;                 // darkness level to pass to Z                                    //
2411 //                                                                                                    //
2412 ////////////////////////////////////////////////////////////////////////////////////////////////////////
2413 
2414 
2415 #define SETRGB16_AA(x,y,Z,Y) {                                                                         \
2416 	                                                                                                   \
2417 	 xx=(x)>>3;                                                /*   turn x coord into byte offset */   \
2418 	                                                                                                   \
2419 	 a3=(yoffset[screen_to_mouse[ y           ]]+xx) &32767;   /*   this value we're processing   */   \
2420 	                                                                                                   \
2421 	 val=(lisaram[videolatchaddress+a3]<<8 )|lisaram[videolatchaddress+a3+1];  /*   this word     */   \
2422                                                                                                        \
2423      if (videoramdirty>DIRECT_BLITS_THRESHHOLD ||        /*  If full update requested or dirty    */   \
2424          (dirtyvidram[a3]<<8)|dirtyvidram[a3+1]!=val  )                                                \
2425       {                                   	                                                           \
2426        updated++;     	                                 /*  Keep track of update count           */   \
2427                                                                                                        \
2428 	   dirty_x_min=MIN(x,dirty_x_min);       dirty_x_max=MAX(x+16,dirty_x_max);                        \
2429 	   dirty_y_min=MIN(y,dirty_y_min);  	 dirty_y_max=MAX(y,dirty_y_max);                           \
2430                                                                                                        \
2431        d=bright[ ((BIT15 & val ) ? 7:0)  ]; Z; x++;                                                    \
2432        d=bright[ ((BIT14 & val ) ? 7:0)  ]; Z; x++;                                                    \
2433        d=bright[ ((BIT13 & val ) ? 7:0)  ]; Z; x++;                                                    \
2434        d=bright[ ((BIT12 & val ) ? 7:0)  ]; Z; x++;                                                    \
2435        d=bright[ ((BIT11 & val ) ? 7:0)  ]; Z; x++;                                                    \
2436        d=bright[ ((BIT10 & val ) ? 7:0)  ]; Z; x++;                                                    \
2437        d=bright[ ((BIT9  & val ) ? 7:0)  ]; Z; x++;                                                    \
2438        d=bright[ ((BIT8  & val ) ? 7:0)  ]; Z; x++;                                                    \
2439        d=bright[ ((BIT7  & val ) ? 7:0)  ]; Z; x++;                                                    \
2440        d=bright[ ((BIT6  & val ) ? 7:0)  ]; Z; x++;                                                    \
2441        d=bright[ ((BIT5  & val ) ? 7:0)  ]; Z; x++;                                                    \
2442        d=bright[ ((BIT4  & val ) ? 7:0)  ]; Z; x++;                                                    \
2443        d=bright[ ((BIT3  & val ) ? 7:0)  ]; Z; x++;                                                    \
2444        d=bright[ ((BIT2  & val ) ? 7:0)  ]; Z; x++;                                                    \
2445        d=bright[ ((BIT1  & val ) ? 7:0)  ]; Z; x++;                                                    \
2446        d=bright[ ((BIT0  & val ) ? 7:0)  ]; Z; x++;                                                    \
2447       } 	                                                                                           \
2448      else                                                                                              \
2449       {                                                                                                \
2450 	    Y; x++;  Y; x++;  Y; x++;  Y; x++;                                                             \
2451 	    Y; x++;  Y; x++;  Y; x++;  Y; x++;                                                             \
2452 	    Y; x++;  Y; x++;  Y; x++;  Y; x++;                                                             \
2453 	    Y; x++;  Y; x++;  Y; x++;  Y; x++;                                                             \
2454 	  }                                                                                                \
2455 }                                                                                                     //
2456 ////////////////// GETRGB MACRO ENDS ///////////////////////////////////////////////////////////////////
2457 
2458 
RePaint_AntiAliased(void)2459 void LisaWin::RePaint_AntiAliased(void)
2460 {
2461    // vars for SETRGB16
2462    int updated=0;
2463    uint32 a3,xx;
2464    uint16 val;
2465    uint8  d;
2466 
2467    dirty_x_min=720; dirty_x_max=-1; dirty_y_min=384*3; dirty_y_max=-1;
2468 
2469 #ifdef USE_RAW_BITMAP_ACCESS
2470 
2471    int depth;
2472    int width;
2473    int height;
2474    int ox,oy; // private to this - not member vars
2475 
2476    if (skins_on)
2477       {
2478 	   if (!my_skin) {ALERT_LOG(0,"Null my_skin"); return;}
2479        depth = my_skin->GetDepth();    width = my_skin->GetWidth();    height= my_skin->GetHeight();
2480        ox=screen_origin_x;    oy=screen_origin_y;
2481       }
2482    else
2483       {
2484 	    if (!my_lisabitmap->IsOk()) {ALERT_LOG(0,"my_lisabitmap is not ok!");}
2485 		if (!my_lisabitmap) {ALERT_LOG(0,"Null my_lisa_bitmap!"); return;}
2486        depth = my_lisabitmap->GetDepth();    width = my_lisabitmap->GetWidth();    height= my_lisabitmap->GetHeight();
2487        ox=0; oy=0;
2488       }
2489 
2490    typedef wxPixelData<wxBitmap,wxNativePixelFormat> PixelData;
2491    PixelData data( *( skins_on ? my_skin : my_lisabitmap) );
2492    if (!data) {ALERT_LOG(0,"No data."); return;}
2493 
2494    PixelData::Iterator p(data);
2495    p.Reset(data);
2496    p.MoveTo(data,ox,oy);
2497 
2498    for ( int y =0; y< effective_lisa_vid_size_y; y++ )   // effective_lisa_vid_size_y
2499    {
2500        PixelData::Iterator rowStart = p;                 // save the x,y coordinates at the start of the line
2501 	   for ( int x = 0; x < effective_lisa_vid_size_x; )
2502 		{ SETRGB16_AA(x,y,  {p.Red()=d; p.Green()=d; p.Blue()=(d+EXTRABLUE); ++p;} , {++p;} );}
2503 	   p = rowStart; p.OffsetY(data, 1);                 // restore the x,y coords from start of line, then increment y to do y++;
2504    }
2505 
2506     /////////////////////////////////////////////////////////////////////////////////////////////////
2507 
2508 #else
2509 
2510   // Since we're working the slower way - with images, we need to rebuild the bitmap from the image.
2511   // to do this, we discard the old bitmap and recreate it from the display_image.  This is of course
2512   // slower, which is why we recommend the use of USE_RAW_BITMAP_ACCESS, but USE_RAW_BITMAP_ACCESS
2513   // might not work everywhere, so we give the option.
2514   if (skins_on)
2515   {
2516     if (!my_skin || !my_lisabitmap) return;
2517 
2518 //    int depth = my_skin->GetDepth();
2519 //    int width = my_skin->GetWidth();
2520 //    int height= my_skin->GetHeight();
2521 
2522  	if (!display_image)
2523          display_image= new wxImage(  my_lisabitmap->ConvertToImage());
2524 
2525 	for ( int y=0; y < effective_lisa_vid_size_y; y++ )
2526 	    {
2527 		    for ( int x=0; x < effective_lisa_vid_size_x;)
2528                 { SETRGB16_AA(x,y,{display_image->SetRGB(x,y,d,d,d+EXTRABLUE); },{;}); }
2529 	    }
2530     // delete the old bitmap, then create a new one from the wxImage, and use it.
2531     delete my_lisabitmap;
2532 	my_lisabitmap=new wxBitmap(*display_image);
2533 	my_memDC->SelectObjectAsSource(*my_lisabitmap);
2534 	   if (!my_memDC->IsOk()) ALERT_LOG(0,"my_memDC is not ok.");
2535 	   if (!my_lisabitmap->IsOk()) ALERT_LOG(0,"my_lisabitmap is not ok.");
2536 
2537     e_dirty_x_min=dirty_x_min;                       // need to do these here so we can update just the rectangle we need.
2538     e_dirty_x_max=dirty_x_max;                       // it will be repeated again below, but so what, it's only 4 assignments
2539     e_dirty_y_min=dirty_y_min; //screen_y_map[dirty_y_min];         // and two lookups.
2540     e_dirty_y_max=dirty_y_max; //screen_y_map[dirty_y_max];
2541 
2542     if (updated)
2543           my_skinDC->Blit(screen_origin_x + e_dirty_x_min, screen_origin_y + e_dirty_y_min,     // target x,y
2544                           e_dirty_x_max-e_dirty_x_min+1,   e_dirty_y_max-e_dirty_y_min+1,     // size w,h
2545                           my_memDC, 0,0, wxCOPY, false);
2546 
2547 
2548     // we don't delete display_image since we can reuse it the next time around and save time
2549   }
2550   else  // skins are off
2551   {
2552     //int depth = my_lisabitmap->GetDepth();
2553     //int width = my_lisabitmap->GetWidth();
2554     //int height= my_lisabitmap->GetHeight();
2555 
2556     if (!display_image)   display_image= new wxImage(my_lisabitmap->ConvertToImage());
2557 
2558 	for ( int yo = 0 , yi=0; yi < effective_lisa_vid_size_y; yo++,yi++ )
2559 	    {
2560 		   // note neither xi, nor xo are incremented as part of the for-loop header, this is because
2561 		   // the SETRGB16_AA macro expands to 16 iterations, and it increments xi on each iteration.
2562 		   // however, it doesn't do anything with xo, so xo++ is passed as a parameter.
2563 		   for ( int xo = 0, xi=0; xi < effective_lisa_vid_size_x;)
2564                { SETRGB16_AA(xi,yi,{display_image->SetRGB(xo,yo,d,d,d+EXTRABLUE); xo++;},{xo++;});   }
2565 	    }
2566 
2567     // and this is why this is slower since we need to rebuild the bitmap from the wxImage each time.
2568 	delete my_lisabitmap;
2569 	my_lisabitmap=new wxBitmap(*display_image);
2570 	my_memDC->SelectObjectAsSource(*my_lisabitmap);
2571   }
2572 #endif
2573 /////////////////////////////////////////////////////////////////////////
2574 
2575   e_dirty_x_min=dirty_x_min;                       // need to do these here so we can update just the rectangle we need.
2576   e_dirty_x_max=dirty_x_max;                       // it will be repeated again below, but so what, it's only 4 assignments
2577   e_dirty_y_min=dirty_y_min; //screen_y_map[dirty_y_min];         // and two lookups.
2578   e_dirty_y_max=dirty_y_max; //screen_y_map[dirty_y_max];
2579 
2580    if (updated)
2581    {
2582       memcpy(dirtyvidram,&lisaram[videolatchaddress],32768);
2583       repaintall |= REPAINT_INVALID_WINDOW | REPAINT_VIDEO_TO_SKIN;
2584 	  updated=0;
2585    }
2586 
2587 }
2588 
2589 ///////////////// SETRGB 16 bit Raw Replacement MACRO //////////////////////////////////////////////////
2590 //                                                                                                    //
2591 //  macro to fill in r,g,b values, does 16 pixels at a time, must be a macro because of the Z param   //
2592 //  and we want to get as much speed out of it as possible.                                           //
2593 //                                                                                                    //
2594 //  This would have been a 32 pixel macro if it were possible, however, since a single row is on the  //
2595 //  Lisa's display is either 90 bytes or 76 bytes, we can only evenly divide by 2 bytes (16 bits.)    //
2596 //                                                                                                    //
2597 //                                                                                                    //
2598 //  x,y are x,y coordinates on the bitmap.   They map to the Lisa's display, any other translation    //
2599 //  must be handled in Z, or via other variables.   x gets incremented for each pixel handled.        //
2600 //  x,y must be simple variables, and should not be expressions!                                      //
2601 //                                                                                                    //
2602 //  Z is a chunk of code to set r,g,b provided by the caller.  Z gets executed 16 times, once per     //
2603 //  pixel.  This is needed because we might be using SetRGB on images or rawbitmap accesss, or some   //
2604 //  other method in the future.   Z should be protected by enclosing it in curly braces when passing. //
2605 //  Z may use the uint8 d to actually set the darkness level for a pixel.                             //
2606 //                                                                                                    //
2607 //  Y is identical to Z except that it's code to call when there's no update.  i.e. ++p               //
2608 //                                                                                                    //
2609 //                                                                                                    //
2610 //  The following variables should be declared before calling this macro:                             //
2611 //                                                                                                    //
2612 //         int updated=0;	        // number of times we've made updates.                            //
2613 //                                  // can be used as a threshhold to decide how to redraw the image. //
2614 //         uint32 a1,a2,a3,xx;      // address above, below, for this value, horziontal byte offset   //
2615 //         uint16 vup,vdn,val;      // value above, below, this words read from addr @ a1,a2,a3       //
2616 //         uint16 high,medium,low;  // used for antialiasing. how many neighboring bits               //
2617 //         uint8 d;                 // darkness level to pass to Z                                    //
2618 //                                                                                                    //
2619 ////////////////////////////////////////////////////////////////////////////////////////////////////////
2620 
2621 #define SETRGB16_RAW_X(x,y,Z) {                                                                        \
2622 	                                                                                                   \
2623 	 xx=(x)>>3;                                                /*   turn x coord into byte offset */   \
2624 	                                                                                                   \
2625 	 a3=(yoffset[y]+xx) &32767;                                /*   this value we're processing   */   \
2626 	 val=(lisaram[videolatchaddress+a3]<<8 )|lisaram[videolatchaddress+a3+1];  /*   this word     */   \
2627                                                                                                        \
2628        updated++;     	                                      /*  Keep track of update count      */   \
2629                                                                                                        \
2630 	   dirty_x_min=MIN(x,dirty_x_min);       dirty_x_max=MAX(x+16,dirty_x_max);                        \
2631 	   dirty_y_min=MIN(y,dirty_y_min);  	 dirty_y_max=MAX(y,dirty_y_max);                           \
2632                                                                                                        \
2633 	                                                                                                   \
2634        d=bright[ ((BIT15 & val) ? 7:0) ]; Z; x++;                                                      \
2635        d=bright[ ((BIT14 & val) ? 7:0) ]; Z; x++;                                                      \
2636        d=bright[ ((BIT13 & val) ? 7:0) ]; Z; x++;                                                      \
2637        d=bright[ ((BIT12 & val) ? 7:0) ]; Z; x++;                                                      \
2638        d=bright[ ((BIT11 & val) ? 7:0) ]; Z; x++;                                                      \
2639        d=bright[ ((BIT10 & val) ? 7:0) ]; Z; x++;                                                      \
2640        d=bright[ ((BIT9  & val) ? 7:0) ]; Z; x++;                                                      \
2641        d=bright[ ((BIT8  & val) ? 7:0) ]; Z; x++;                                                      \
2642        d=bright[ ((BIT7  & val) ? 7:0) ]; Z; x++;                                                      \
2643        d=bright[ ((BIT6  & val) ? 7:0) ]; Z; x++;                                                      \
2644        d=bright[ ((BIT5  & val) ? 7:0) ]; Z; x++;                                                      \
2645        d=bright[ ((BIT4  & val) ? 7:0) ]; Z; x++;                                                      \
2646        d=bright[ ((BIT3  & val) ? 7:0) ]; Z; x++;                                                      \
2647        d=bright[ ((BIT2  & val) ? 7:0) ]; Z; x++;                                                      \
2648        d=bright[ ((BIT1  & val) ? 7:0) ]; Z; x++;                                                      \
2649        d=bright[ ((BIT0  & val) ? 7:0) ]; Z; x++;                                                      \
2650 }                                                                                                     //
2651 ////////////////// SETRGB MACRO ENDS ///////////////////////////////////////////////////////////////////
2652 
2653 
2654 ///////////////// SETRGB 16 bit Raw Replacement MACRO //////////////////////////////////////////////////
2655 //                                                                                                    //
2656 //  macro to fill in r,g,b values, does 16 pixels at a time, must be a macro because of the Z param   //
2657 //  and we want to get as much speed out of it as possible.                                           //
2658 //                                                                                                    //
2659 //  This would have been a 32 pixel macro if it were possible, however, since a single row is on the  //
2660 //  Lisa's display is either 90 bytes or 76 bytes, we can only evenly divide by 2 bytes (16 bits.)    //
2661 //                                                                                                    //
2662 //                                                                                                    //
2663 //  x,y are x,y coordinates on the bitmap.   They map to the Lisa's display, any other translation    //
2664 //  must be handled in Z, or via other variables.   x gets incremented for each pixel handled.        //
2665 //  x,y must be simple variables, and should not be expressions!                                      //
2666 //                                                                                                    //
2667 //  Z is a chunk of code to set r,g,b provided by the caller.  Z gets executed 16 times, once per     //
2668 //  pixel.  This is needed because we might be using SetRGB on images or rawbitmap accesss, or some   //
2669 //  other method in the future.   Z should be protected by enclosing it in curly braces when passing. //
2670 //  Z may use the uint8 d to actually set the darkness level for a pixel.                             //
2671 //                                                                                                    //
2672 //  Y is identical to Z except that it's code to call when there's no update.  i.e. ++p               //
2673 //                                                                                                    //
2674 //                                                                                                    //
2675 //  The following variables should be declared before calling this macro:                             //
2676 //                                                                                                    //
2677 //         int updated=0;	        // number of times we've made updates.                            //
2678 //                                  // can be used as a threshhold to decide how to redraw the image. //
2679 //         uint32 a1,a2,a3,xx;      // address above, below, for this value, horziontal byte offset   //
2680 //         uint16 vup,vdn,val;      // value above, below, this words read from addr @ a1,a2,a3       //
2681 //         uint16 high,medium,low;  // used for antialiasing. how many neighboring bits               //
2682 //         uint8 d;                 // darkness level to pass to Z                                    //
2683 //                                                                                                    //
2684 ////////////////////////////////////////////////////////////////////////////////////////////////////////
2685 
2686 #define SETRGB16_RAW(x,y,Z,Y) {                                                                        \
2687 	                                                                                                   \
2688 	 xx=(x)>>3;                                                /*   turn x coord into byte offset */   \
2689 	                                                                                                   \
2690 	 a3=(yoffset[screen_to_mouse[ y           ]]+xx) &32767;   /*   this value we're processing   */   \
2691 	 val=(lisaram[videolatchaddress+a3]<<8 )|lisaram[videolatchaddress+a3+1];  /*   this word     */   \
2692                                                                                                        \
2693      if (videoramdirty>DIRECT_BLITS_THRESHHOLD ||        /*  If full update requested or          */   \
2694          (dirtyvidram[a3]<<8)|dirtyvidram[a3+1]!=val  )  /*  value is changed                     */   \
2695       {                                   	                                                           \
2696        updated++;     	                                 /*  Keep track of update count           */   \
2697                                                                                                        \
2698 	   dirty_x_min=MIN(x,dirty_x_min);       dirty_x_max=MAX(x+16,dirty_x_max);                        \
2699 	   dirty_y_min=MIN(y,dirty_y_min);  	 dirty_y_max=MAX(y,dirty_y_max);                           \
2700                                                                                                        \
2701 	                                                                                                   \
2702        d=bright[ ((BIT15 & val) ? 7:0) ]; Z; x++;                                                      \
2703        d=bright[ ((BIT14 & val) ? 7:0) ]; Z; x++;                                                      \
2704        d=bright[ ((BIT13 & val) ? 7:0) ]; Z; x++;                                                      \
2705        d=bright[ ((BIT12 & val) ? 7:0) ]; Z; x++;                                                      \
2706        d=bright[ ((BIT11 & val) ? 7:0) ]; Z; x++;                                                      \
2707        d=bright[ ((BIT10 & val) ? 7:0) ]; Z; x++;                                                      \
2708        d=bright[ ((BIT9  & val) ? 7:0) ]; Z; x++;                                                      \
2709        d=bright[ ((BIT8  & val) ? 7:0) ]; Z; x++;                                                      \
2710        d=bright[ ((BIT7  & val) ? 7:0) ]; Z; x++;                                                      \
2711        d=bright[ ((BIT6  & val) ? 7:0) ]; Z; x++;                                                      \
2712        d=bright[ ((BIT5  & val) ? 7:0) ]; Z; x++;                                                      \
2713        d=bright[ ((BIT4  & val) ? 7:0) ]; Z; x++;                                                      \
2714        d=bright[ ((BIT3  & val) ? 7:0) ]; Z; x++;                                                      \
2715        d=bright[ ((BIT2  & val) ? 7:0) ]; Z; x++;                                                      \
2716        d=bright[ ((BIT1  & val) ? 7:0) ]; Z; x++;                                                      \
2717        d=bright[ ((BIT0  & val) ? 7:0) ]; Z; x++;                                                      \
2718       } 	                                                                                           \
2719      else                                                                                              \
2720       {                                                                                                \
2721 	    Y; x++;  Y; x++;  Y; x++;  Y; x++;                                                             \
2722 	    Y; x++;  Y; x++;  Y; x++;  Y; x++;                                                             \
2723 	    Y; x++;  Y; x++;  Y; x++;  Y; x++;                                                             \
2724 	    Y; x++;  Y; x++;  Y; x++;  Y; x++;                                                             \
2725 	  }                                                                                                \
2726 }                                                                                                     //
2727 ////////////////// SETRGB MACRO ENDS ///////////////////////////////////////////////////////////////////
2728 
RePaint_SingleY(void)2729 void LisaWin::RePaint_SingleY(void)
2730 {
2731    // vars for SETRGB16_RAW
2732    int updated=0;
2733    uint32 a3,xx;
2734    uint16 val;
2735    uint8  d;
2736 
2737    dirty_x_min=720; dirty_x_max=-1; dirty_y_min=384*3; dirty_y_max=-1;
2738 
2739 #ifdef USE_RAW_BITMAP_ACCESS
2740 
2741  int depth;
2742  int width;
2743  int height;
2744  int ox,oy; // private to this - not member vars
2745 
2746 
2747 if (skins_on)
2748    {
2749     if (!my_skin) return;
2750     depth = my_skin->GetDepth();    width = my_skin->GetWidth();    height= my_skin->GetHeight();
2751     ox=screen_origin_x;    oy=screen_origin_y;
2752    }
2753 else
2754    {
2755     if (!my_lisabitmap) return;
2756     depth = my_lisabitmap->GetDepth();    width = my_lisabitmap->GetWidth();    height= my_lisabitmap->GetHeight();
2757     ox=0; oy=0;
2758    }
2759 
2760    typedef wxPixelData<wxBitmap,wxNativePixelFormat> PixelData;
2761    PixelData data(skins_on ? *my_skin:*my_lisabitmap);
2762    if (!data) {DEBUG_LOG(0,"No data."); return;}
2763 
2764    PixelData::Iterator p(data);
2765    p.Reset(data);
2766 
2767    p.MoveTo(data,ox,oy);
2768    for ( int y = 0; y < effective_lisa_vid_size_y; ++y )
2769    {
2770        PixelData::Iterator rowStart = p;              // save the x,y coordinates at the start of the line
2771 	   for ( int x = 0; x < effective_lisa_vid_size_x; )
2772 	       { SETRGB16_RAW(x,y,  {p.Red()=d; p.Green()=d; p.Blue()=(d+EXTRABLUE); ++p;} , {++p;} );}
2773 
2774        p = rowStart; p.OffsetY(data, 1);              // restore the x,y coords from start of line, then increment y via P.OffsetY to do y++;
2775    }
2776 
2777 #else
2778 
2779   // Since we're working the slower way - with images, we need to rebuild the bitmap from the image.
2780   // to do this, we discard the old bitmap and recreate it from the display_image.  This is of course
2781   // slower, which is why we recommend the use of USE_RAW_BITMAP_ACCESS, but USE_RAW_BITMAP_ACCESS
2782   // might not work everywhere, so we give the option.
2783   if (skins_on)
2784   {
2785     if (!my_skin || !my_lisabitmap) return;
2786 
2787     //int depth = my_skin->GetDepth();
2788     //int width = my_skin->GetWidth();
2789     //int height= my_skin->GetHeight();
2790 
2791  	if (!display_image)
2792          display_image= new wxImage(  my_lisabitmap->ConvertToImage());
2793 
2794 	for ( int y=0; y < effective_lisa_vid_size_y; y++ )
2795 	    {
2796 		   // note neither xi, nor xo are incremented as part of the for-loop header, this is because
2797 		   // the SETRGB16_AA macro expands to 16 iterations, and it increments xi on each iteration.
2798 		   // however, it doesn't do anything with xo, so xo++ is passed as a parameter.
2799 		    for ( int x=0; x < effective_lisa_vid_size_x;)
2800                 { SETRGB16_RAW(x,y,{display_image->SetRGB(x,y,d,d,d+EXTRABLUE); },{;}); }
2801 	    }
2802 
2803     delete my_lisabitmap;
2804 	my_lisabitmap=new wxBitmap(*display_image);
2805 	my_memDC->SelectObjectAsSource(*my_lisabitmap);
2806 
2807     e_dirty_x_min=dirty_x_min;                       // need to do these here so we can update just the rectangle we need.
2808     e_dirty_x_max=dirty_x_max;                       // it will be repeated again below, but so what, it's only 4 assignments
2809     e_dirty_y_min=dirty_y_min; //screen_y_map[dirty_y_min];         // and two lookups.
2810     e_dirty_y_max=dirty_y_max; //screen_y_map[dirty_y_max];
2811 
2812     if (updated)
2813          my_skinDC->Blit(screen_origin_x + e_dirty_x_min, screen_origin_y+e_dirty_y_min,     // target x,y
2814                     e_dirty_x_max-e_dirty_x_min+1,   e_dirty_y_max-e_dirty_y_min+1,     // size w,h
2815                     my_memDC, 0,0, wxCOPY, false);
2816 
2817   }
2818  else  // skins are off
2819   {
2820     //int depth = my_lisabitmap->GetDepth();
2821     //int width = my_lisabitmap->GetWidth();
2822     //int height= my_lisabitmap->GetHeight();
2823 
2824     if (!display_image)   display_image= new wxImage(my_lisabitmap->ConvertToImage());
2825 
2826 	for ( int yo = 0 , yi=0; yi < effective_lisa_vid_size_y; yo++,yi++ )
2827 	    {
2828 		   // note neither xi, nor xo are incremented as part of the for-loop header, this is because
2829 		   // the SETRGB16_AA macro expands to 16 iterations, and it increments xi on each iteration.
2830 		   // however, it doesn't do anything with xo, so xo++ is passed as a parameter.
2831 		   for ( int xo = 0, xi=0; xi < effective_lisa_vid_size_x;)
2832                { SETRGB16_RAW(xi,yi,{display_image->SetRGB(xo,yo,d,d,d+EXTRABLUE); xo++;},{xo++;});   }
2833 	    }
2834 
2835 	delete my_lisabitmap;
2836 	my_lisabitmap=new wxBitmap(*display_image);
2837 	my_memDC->SelectObjectAsSource(*my_lisabitmap);
2838   }
2839 #endif
2840 /////////////////////////////////////////////////////////////////////////
2841 
2842   e_dirty_x_min=dirty_x_min;                       // need to do these here so we can update just the rectangle we need.
2843   e_dirty_x_max=dirty_x_max;                       // it will be repeated again below, but so what, it's only 4 assignments
2844   e_dirty_y_min=dirty_y_min; //screen_y_map[dirty_y_min];         // and two lookups.
2845   e_dirty_y_max=dirty_y_max; //screen_y_map[dirty_y_max];
2846 
2847 
2848   if (updated)
2849   {
2850       memcpy(dirtyvidram,&lisaram[videolatchaddress],32768);
2851       repaintall |= REPAINT_INVALID_WINDOW | REPAINT_VIDEO_TO_SKIN;
2852 	  updated=0;
2853   }
2854 
2855 
2856 }
2857 
2858 // this is essentially the same as SingleY, only for a differently sized display.
RePaint_3A(void)2859 void LisaWin::RePaint_3A(void)
2860 {
2861    // vars for SETRGB16_RAW
2862    int updated=0;
2863    uint32 a3,xx;
2864    uint16 val;
2865    uint8  d;
2866 
2867    dirty_x_min=720; dirty_x_max=-1; dirty_y_min=384*3; dirty_y_max=-1;
2868 
2869 #ifdef USE_RAW_BITMAP_ACCESS
2870 
2871  int depth;
2872  int width;
2873  int height;
2874  int ox,oy; // private to this - not member vars
2875 
2876 
2877 if (skins_on)
2878    {
2879     if (!my_skin) return;
2880     depth = my_skin->GetDepth();    width = my_skin->GetWidth();    height= my_skin->GetHeight();
2881     ox=screen_origin_x;    oy=screen_origin_y;
2882    }
2883 else
2884    {
2885     if (!my_lisabitmap) return;
2886     depth = my_lisabitmap->GetDepth();    width = my_lisabitmap->GetWidth();    height= my_lisabitmap->GetHeight();
2887     ox=0; oy=0;
2888    }
2889 
2890    typedef wxPixelData<wxBitmap,wxNativePixelFormat> PixelData;
2891    PixelData data(skins_on ? *my_skin:*my_lisabitmap);
2892 
2893    PixelData::Iterator p(data);
2894    p.Reset(data);
2895    p.MoveTo(data,ox,oy);
2896 
2897    for ( int y = 0; y < effective_lisa_vid_size_y; ++y )   // effective_lisa_vid_size_y
2898    {
2899        PixelData::Iterator rowStart = p;                   // save the x,y coordinates at the start of the line
2900 
2901 	   for ( int x = 0; x < effective_lisa_vid_size_x; )
2902 	       { SETRGB16_RAW(x,y,  {p.Red()=d; p.Green()=d; p.Blue()=(d+EXTRABLUE); ++p;} , {++p;} );}
2903 
2904        p = rowStart; p.OffsetY(data, 1);                   // restore the x,y coords from start of line, then increment y to do y++;
2905    }
2906 
2907 #else
2908 
2909   // Since we're working the slower way - with images, we need to rebuild the bitmap from the image.
2910   // to do this, we discard the old bitmap and recreate it from the display_image.  This is of course
2911   // slower, which is why we recommend the use of USE_RAW_BITMAP_ACCESS, but USE_RAW_BITMAP_ACCESS
2912   // might not work everywhere, so we give the option.
2913   if (skins_on)
2914   {
2915     if (!my_skin || !my_lisabitmap) return;
2916 
2917     //int depth = my_skin->GetDepth();
2918     //int width = my_skin->GetWidth();
2919     //int height= my_skin->GetHeight();
2920 
2921  	if (!display_image)
2922          display_image= new wxImage(  my_lisabitmap->ConvertToImage());
2923 
2924 	for ( int y=0; y < effective_lisa_vid_size_y; y++ )
2925 	    {
2926 		   // note neither xi, nor xo are incremented as part of the for-loop header, this is because
2927 		   // the SETRGB16_AA macro expands to 16 iterations, and it increments xi on each iteration.
2928 		   // however, it doesn't do anything with xo, so xo++ is passed as a parameter.
2929 		    for ( int x=0; x < effective_lisa_vid_size_x;)
2930                 { SETRGB16_RAW(x,y,{display_image->SetRGB(x,y,d,d,d+EXTRABLUE); },{;}); }
2931 	    }
2932 
2933     delete my_lisabitmap;
2934 	my_lisabitmap=new wxBitmap(*display_image);
2935 	my_memDC->SelectObjectAsSource(*my_lisabitmap);
2936 
2937     e_dirty_x_min=dirty_x_min;                       // need to do these here so we can update just the rectangle we need.
2938     e_dirty_x_max=dirty_x_max;                       // it will be repeated again below, but so what, it's only 4 assignments
2939     e_dirty_y_min=dirty_y_min; //screen_y_map[dirty_y_min];         // and two lookups.
2940     e_dirty_y_max=dirty_y_max; //screen_y_map[dirty_y_max];
2941 
2942     if (updated)
2943         my_skinDC->Blit(screen_origin_x + e_dirty_x_min, screen_origin_y+e_dirty_y_min,     // target x,y
2944                     e_dirty_x_max-e_dirty_x_min+1,   e_dirty_y_max-e_dirty_y_min+1,     // size w,h
2945                    my_memDC, 0,0, wxCOPY, false);
2946   }
2947   else  // skins are off
2948   {
2949     //int depth = my_lisabitmap->GetDepth();
2950     //int width = my_lisabitmap->GetWidth();
2951     //int height= my_lisabitmap->GetHeight();
2952 
2953     if (!display_image)   display_image= new wxImage(my_lisabitmap->ConvertToImage());
2954 
2955 	for ( int y=0; y < effective_lisa_vid_size_y; y++ )
2956 	    {
2957 		   // note neither xi, nor xo are incremented as part of the for-loop header, this is because
2958 		   // the SETRGB16_AA macro expands to 16 iterations, and it increments xi on each iteration.
2959 		   // however, it doesn't do anything with xo, so xo++ is passed as a parameter.
2960 		   //for ( int xo = 0, xi=0; xi < effective_lisa_vid_size_x;)
2961                // { SETRGB16_RAW(xi,yi,{display_image->SetRGB(xo,yo,d,d,d+EXTRABLUE); xo++;},{xo++;});   }
2962 		    for ( int x=0; x < effective_lisa_vid_size_x;)
2963                 { SETRGB16_RAW(x,y,{display_image->SetRGB(x,y,d,d,d+EXTRABLUE); },{;}); }
2964 	    }
2965 
2966 	delete my_lisabitmap;
2967 	my_lisabitmap=new wxBitmap(*display_image);
2968 	my_memDC->SelectObjectAsSource(*my_lisabitmap);
2969   }
2970 #endif
2971 /////////////////////////////////////////////////////////////////////////
2972 
2973   e_dirty_x_min=dirty_x_min;                       // need to do these here so we can update just the rectangle we need.
2974   e_dirty_x_max=dirty_x_max;                       // it will be repeated again below, but so what, it's only 4 assignments
2975   e_dirty_y_min=dirty_y_min; //screen_y_map[dirty_y_min];         // and two lookups.
2976   e_dirty_y_max=dirty_y_max; //screen_y_map[dirty_y_max];
2977 
2978   if (updated)
2979   {
2980       memcpy(dirtyvidram,&lisaram[videolatchaddress],32768);
2981       repaintall |= REPAINT_INVALID_WINDOW | REPAINT_VIDEO_TO_SKIN;
2982 	  updated=0;
2983   }
2984 
2985 
2986 }
2987 
2988 
2989 // no skins here.
RePaint_DoubleY(void)2990 void LisaWin::RePaint_DoubleY(void)
2991 {
2992    // vars for SETRGB16_RAW
2993    int updated=0;
2994    uint32 a3,xx;
2995    uint16 val;
2996    uint8  d;
2997 
2998 
2999    if (skins_on) {ALERT_LOG(0,"Skins should not be on!!!!"); turn_skins_off();}
3000    if (!my_lisabitmap) return;
3001    dirty_x_min=720; dirty_x_max=-1; dirty_y_min=384*3; dirty_y_max=-1;
3002 
3003 #ifdef USE_RAW_BITMAP_ACCESS
3004 
3005    int depth;
3006    int width;
3007    int height;
3008    int ox,oy; // private to this - not member vars
3009 
3010    if (!my_lisabitmap) return;
3011    depth = my_lisabitmap->GetDepth();    width = my_lisabitmap->GetWidth();    height= my_lisabitmap->GetHeight();
3012    ox=0; oy=0;
3013 
3014    typedef wxPixelData<wxBitmap,wxNativePixelFormat> PixelData;
3015    PixelData data(*my_lisabitmap);
3016    if (!data) return;
3017 
3018    PixelData::Iterator p(data);
3019    p.Reset(data);
3020    p.MoveTo(data,ox,oy);
3021 
3022    for ( int y = 0; y < effective_lisa_vid_size_y; ++y )   // effective_lisa_vid_size_y
3023    {
3024        PixelData::Iterator rowStart = p;                   // save the x,y coordinates at the start of the line
3025 
3026 	   for ( int x = 0; x < effective_lisa_vid_size_x; )
3027 	       { SETRGB16_RAW(x,y,  {p.Red()=d; p.Green()=d; p.Blue()=(d+EXTRABLUE); ++p;} , {++p;} );}
3028 
3029        p = rowStart; p.OffsetY(data, 1);                   // restore the x,y coords from start of line, then increment y to do y++;
3030    }
3031 
3032 #else
3033 
3034   // Since we're working the slower way - with images, we need to rebuild the bitmap from the image.
3035   // to do this, we discard the old bitmap and recreate it from the display_image.  This is of course
3036   // slower, which is why we recommend the use of USE_RAW_BITMAP_ACCESS, but USE_RAW_BITMAP_ACCESS
3037   // might not work everywhere, so we give the option.
3038 //  int depth = my_lisabitmap->GetDepth();
3039 //  int width = my_lisabitmap->GetWidth();
3040 //  int height= my_lisabitmap->GetHeight();
3041 
3042   if (!display_image)   display_image= new wxImage(my_lisabitmap->ConvertToImage());
3043 
3044   for ( int y=0; y < effective_lisa_vid_size_y; y++)
3045       {
3046 	    for ( int x=0; x < effective_lisa_vid_size_x;)
3047             { SETRGB16_RAW(x,y,{display_image->SetRGB(x,y,d,d,d+EXTRABLUE); },{;}); }
3048       }
3049 
3050   delete my_lisabitmap;
3051   my_lisabitmap=new wxBitmap(*display_image);
3052   my_memDC->SelectObjectAsSource(*my_lisabitmap);
3053 
3054 #endif
3055 /////////////////////////////////////////////////////////////////////////
3056 
3057   e_dirty_x_min=dirty_x_min;                       // need to do these here so we can update just the rectangle we need.
3058   e_dirty_x_max=dirty_x_max;                       // it will be repeated again below, but so what, it's only 4 assignments
3059   e_dirty_y_min=dirty_y_min; //screen_y_map[dirty_y_min];         // and two lookups.
3060   e_dirty_y_max=dirty_y_max; //screen_y_map[dirty_y_max];
3061 
3062 
3063   if (updated)
3064   {
3065       memcpy(dirtyvidram,&lisaram[videolatchaddress],32768);
3066       repaintall |= REPAINT_INVALID_WINDOW | REPAINT_VIDEO_TO_SKIN;
3067 	  updated=0;
3068   }
3069 
3070 
3071 }
3072 
3073 
RePaint_2X3Y(void)3074 void LisaWin::RePaint_2X3Y(void)
3075 {
3076 	   // vars for SETRGB16_RAW
3077 	   int updated=0;
3078 	   uint32 a3,xx;
3079 	   uint16 val;
3080 	   uint8  d;
3081 
3082 
3083   	   if (!my_lisabitmap) return;
3084        dirty_x_min=720; dirty_x_max=-1; dirty_y_min=384*3; dirty_y_max=-1;
3085 
3086 #ifdef USE_RAW_BITMAP_ACCESS
3087 
3088 	   int depth;
3089 	   int width;
3090 	   int height;
3091 	   int ox,oy; // private to this - not member vars
3092 
3093 	   if (!my_lisabitmap) return;
3094 	   depth = my_lisabitmap->GetDepth();    width = my_lisabitmap->GetWidth();    height= my_lisabitmap->GetHeight();
3095 	   ox=0; oy=0;
3096 
3097 	   typedef wxPixelData<wxBitmap,wxNativePixelFormat> PixelData;
3098 	   PixelData data(*my_lisabitmap);
3099    	   if (!data) return;
3100 
3101 	   PixelData::Iterator p(data);
3102 	   p.Reset(data);
3103        p.MoveTo(data,ox,oy);
3104 
3105 	   for ( int y = 0; y < effective_lisa_vid_size_y; ++y )   // effective_lisa_vid_size_y
3106 	   {
3107 	       PixelData::Iterator rowStart = p;              // save the x,y coordinates at the start of the line
3108 
3109 		   for ( int x = 0; x < 720; )
3110 		       { SETRGB16_RAW(x,y,  {p.Red()=d; p.Green()=d; p.Blue()=(d+EXTRABLUE); ++p; p.Red()=d; p.Green()=d; p.Blue()=(d+EXTRABLUE); ++p;} ,
3111 		                            {++p;++p;} );}
3112 
3113 		   p = rowStart; p.OffsetY(data, 1);              // restore the x,y coords from start of line, then increment y to do y++;
3114 	   }
3115 
3116 	#else
3117 
3118 	  // Since we're working the slower way - with images, we need to rebuild the bitmap from the image.
3119 	  // to do this, we discard the old bitmap and recreate it from the display_image.  This is of course
3120 	  // slower, which is why we recommend the use of USE_RAW_BITMAP_ACCESS, but USE_RAW_BITMAP_ACCESS
3121 	  // might not work everywhere, so we give the option.
3122 //	  int depth = my_lisabitmap->GetDepth();
3123 //	  int width = my_lisabitmap->GetWidth();
3124 //	  int height= my_lisabitmap->GetHeight();
3125 
3126 	  if (!display_image)   display_image= new wxImage(my_lisabitmap->ConvertToImage());
3127 
3128 	  for ( int yo = 0 , yi=0; yi < effective_lisa_vid_size_y; yo++,yi++ )
3129 	      {
3130 
3131 	  	   for ( int xo = 0, xi=0; xi < 720;)
3132 	             { SETRGB16_RAW(xi,yi,{display_image->SetRGB(xo,yo,d,d,d+EXTRABLUE); xo++; display_image->SetRGB(xo,yo,d,d,d+EXTRABLUE); xo++;},
3133 	                                  {xo++;}  );   }
3134 	      }
3135 
3136 	  delete my_lisabitmap;
3137 	  my_lisabitmap=new wxBitmap(*display_image);
3138 	  my_memDC->SelectObjectAsSource(*my_lisabitmap);
3139 
3140 	#endif
3141 	/////////////////////////////////////////////////////////////////////////
3142 
3143     e_dirty_x_min=dirty_x_min;                       // need to do these here so we can update just the rectangle we need.
3144     e_dirty_x_max=dirty_x_max;                       // it will be repeated again below, but so what, it's only 4 assignments
3145     e_dirty_y_min=dirty_y_min; //screen_y_map[dirty_y_min];         // and two lookups.
3146     e_dirty_y_max=dirty_y_max; //screen_y_map[dirty_y_max];
3147 
3148 	  if (updated)
3149 	  {
3150 	      memcpy(dirtyvidram,&lisaram[videolatchaddress],32768);
3151 	      repaintall |= REPAINT_INVALID_WINDOW | REPAINT_VIDEO_TO_SKIN;
3152 		  updated=0;
3153 	  }
3154 
3155 }
3156 
3157 
3158 
3159 ///////////////// SETRGB 16 bit AntiAliased MACRO //////////////////////////////////////////////////////
3160 //                                                                                                    //
3161 //  macro to fill in r,g,b values, does 16 pixels at a time, must be a macro because of the Z param   //
3162 //  and we want to get as much speed out of it as possible.                                           //
3163 //                                                                                                    //
3164 //  This would have been a 32 pixel macro if it were possible, however, since a single row is on the  //
3165 //  Lisa's display is either 90 bytes or 76 bytes, we can only evenly divide by 2 bytes (16 bits.)    //
3166 //                                                                                                    //
3167 //                                                                                                    //
3168 //  x,y are x,y coordinates on the bitmap.   They map to the Lisa's display, any other translation    //
3169 //  must be handled in Z, or via other variables.   x gets incremented for each pixel handled.        //
3170 //  x,y must be simple variables, and should not be expressions!                                      //
3171 //                                                                                                    //
3172 //  Z is a chunk of code to set r,g,b provided by the caller.  Z gets executed 16 times, once per     //
3173 //  pixel.  This is needed because we might be using SetRGB on images or rawbitmap accesss, or some   //
3174 //  other method in the future.   Z should be protected by enclosing it in curly braces when passing. //
3175 //  Z may use the uint8 d to actually set the darkness level for a pixel.                             //
3176 //                                                                                                    //
3177 //  Y is identical to Z except that it's code to call when there's no update.  i.e. ++p               //
3178 //                                                                                                    //
3179 //                                                                                                    //
3180 //  The following variables should be declared before calling this macro:                             //
3181 //                                                                                                    //
3182 //      int updated=0;	            // number of times we've made updates.                            //
3183 //                                  // can be used as a threshhold to decide how to redraw the image. //
3184 //      uint32 a1,a2,a3,a4,a5,xx;   // address above, below, for this value, horziontal byte offset   //
3185 //      uint16 vup,vdn,val,vvu,vvd; // value above, below, this words read from addr @ a1,a2,a3       //
3186 //      uint16 high,medium,low;     // used for antialiasing. how many neighboring bits               //
3187 //      uint8 d;                    // darkness level to pass to Z                                    //
3188 //                                                                                                    //
3189 ////////////////////////////////////////////////////////////////////////////////////////////////////////
3190 
3191 #define SETRGB16_AAG(x,y,Z,Y) {                                                                        \
3192 	                                                                                                   \
3193 	 xx=(x)>>3;                                                /*   turn x coord into byte offset */   \
3194 	                                                                                                   \
3195 	 a1=(yoffset[screen_to_mouse[ y>0?(y-1):0 ]]+xx) &32767;   /*   get the addresses for above   */   \
3196 	 a2=(yoffset[screen_to_mouse[ y+1         ]]+xx) &32767;   /*   below and                     */   \
3197 	 a3=(yoffset[screen_to_mouse[ y           ]]+xx) &32767;   /*   this value we're processing   */   \
3198 	                                                                                                   \
3199 	 vup=(lisaram[videolatchaddress+a1]<<8 )|lisaram[videolatchaddress+a1+1];  /*   word above    */   \
3200 	 vdn=(lisaram[videolatchaddress+a2]<<8 )|lisaram[videolatchaddress+a2+1];  /*   word below    */   \
3201 	 val=(lisaram[videolatchaddress+a3]<<8 )|lisaram[videolatchaddress+a3+1];  /*   this word     */   \
3202                                                                                                        \
3203                                                                                                        \
3204      if (videoramdirty>DIRECT_BLITS_THRESHHOLD ||        /*  If full update requested or          */   \
3205          (dirtyvidram[a1]<<8)|dirtyvidram[a1+1]!=vup ||  /*  if the video ram is dirty above or   */   \
3206          (dirtyvidram[a2]<<8)|dirtyvidram[a2+1]!=vdn ||  /*  below or on this value.              */   \
3207          (dirtyvidram[a3]<<8)|dirtyvidram[a3+1]!=val  )                                                \
3208       {                                   	                                                           \
3209        updated++;     	                                 /*  Keep track of update count           */   \
3210                                                                                                        \
3211 	   dirty_x_min=MIN(x,dirty_x_min);       dirty_x_max=MAX(x+16,dirty_x_max);                        \
3212 	   dirty_y_min=MIN(y,dirty_y_min);  	 dirty_y_max=MAX(y,dirty_y_max);                           \
3213                                                                                                        \
3214  	   a4=(a3-90)>0     ? (a3-90):a3;                                    /*   unscaled addr above */   \
3215 	   a5=(a3+90)<32767 ? (a3+90):a3;                                    /*   unscaled addr below */   \
3216 	   vvu=(lisaram[videolatchaddress+a4]<<8 )|lisaram[videolatchaddress+a4+1]; /* unscaled up    */   \
3217 	   vvd=(lisaram[videolatchaddress+a5]<<8 )|lisaram[videolatchaddress+a5+1]; /* unscaled below */   \
3218        getgraymap(vvu,val,vvd,replacegray);              /*  Get the gray replacement map         */   \
3219 	                                                                                                   \
3220 	   high   = vup      & val     & vdn;                /*  above, middle, and below are black   */   \
3221 	   medium = (vup&val)|(val&vdn)|(vdn&vup);           /*  two out of 3 are black               */   \
3222 	   low    = vup      | val     | vdn;                /*  lowest - single pixel is black       */   \
3223 	                                                                                                   \
3224 	  d=bright[ ((BIT15 & val ) ? 7:0)  | replacegray[ 0]]; Z; x++;                                    \
3225 	  d=bright[ ((BIT14 & val ) ? 7:0)  | replacegray[ 1]]; Z; x++;                                    \
3226 	  d=bright[ ((BIT13 & val ) ? 7:0)  | replacegray[ 2]]; Z; x++;                                    \
3227 	  d=bright[ ((BIT12 & val ) ? 7:0)  | replacegray[ 3]]; Z; x++;                                    \
3228 	  d=bright[ ((BIT11 & val ) ? 7:0)  | replacegray[ 4]]; Z; x++;                                    \
3229 	  d=bright[ ((BIT10 & val ) ? 7:0)  | replacegray[ 5]]; Z; x++;                                    \
3230 	  d=bright[ ((BIT9  & val ) ? 7:0)  | replacegray[ 6]]; Z; x++;                                    \
3231 	  d=bright[ ((BIT8  & val ) ? 7:0)  | replacegray[ 7]]; Z; x++;                                    \
3232 	  d=bright[ ((BIT7  & val ) ? 7:0)  | replacegray[ 8]]; Z; x++;                                    \
3233 	  d=bright[ ((BIT6  & val ) ? 7:0)  | replacegray[ 9]]; Z; x++;                                    \
3234 	  d=bright[ ((BIT5  & val ) ? 7:0)  | replacegray[10]]; Z; x++;                                    \
3235 	  d=bright[ ((BIT4  & val ) ? 7:0)  | replacegray[11]]; Z; x++;                                    \
3236 	  d=bright[ ((BIT3  & val ) ? 7:0)  | replacegray[12]]; Z; x++;                                    \
3237 	  d=bright[ ((BIT2  & val ) ? 7:0)  | replacegray[13]]; Z; x++;                                    \
3238 	  d=bright[ ((BIT1  & val ) ? 7:0)  | replacegray[14]]; Z; x++;                                    \
3239 	  d=bright[ ((BIT0  & val ) ? 7:0)  | replacegray[15]]; Z; x++;                                    \
3240 	                                                                                                   \
3241 	                                                                                                   \
3242       } 	                                                                                           \
3243      else                                                                                              \
3244       {                                                                      /* No updated needed */   \
3245 	    Y; Y; Y; Y;                                                          /* so skip over 16X  */   \
3246 	    Y; Y; Y; Y;                                                                                    \
3247 	    Y; Y; Y; Y;                                                                                    \
3248 	    Y; Y; Y; Y; x+=16;                                                                             \
3249 	  }                                                                                                \
3250 }                                                                                                     //
3251 ////////////////// GETRGB MACRO ENDS ///////////////////////////////////////////////////////////////////
3252 
3253 /***************************************************************************************************\
3254    graymap[] are set to 8 which is the magical OR value into the color contrast table that forces
3255    gray replacement.  See ContrastChange() for details.  The graymap is stored as a 3 dimentional
3256    array, but we can make use of shifts and OR's to avoid multiplication that [][][] would be
3257    involved in dereferencing.  It's possible some compilers will optimize it properly, but why
3258    take a chance?  Access is equivalent to   color | graymap[(vup<<4) | (val<<2) | vdn];
3259 
3260    Since we work 2 bits at a time, we need to replace both bits with a gray together.  This is why
3261    we have retval[1]=retval[0] and so on.   It would be possible to modify the code to do something
3262    like retval & 14 to avoid the copy, but it wouldn't be any faster and would make the code more
3263    complicated.
3264 
3265    This function is only called once per every 16 horizontal pixels processed for speed which is
3266    why it needs to store its results in an array.
3267 
3268  \***************************************************************************************************/
3269 
getgraymap(uint16 up,uint16 val,uint16 dn,uint8 * retval)3270 static inline void getgraymap(uint16 up, uint16 val, uint16 dn,  uint8 *retval)
3271 {
3272 	static uint8 graymap[4*4*4]={ 0,0,0,0,0,0,8,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,8,0,8,0,8,0,0,
3273 	                              0,0,0,0,8,0,8,8,0,0,0,0,0,0,8,0,0,0,0,0,0,0,8,8,0,8,0,8,0,0,0,0, };
3274 
3275 // static int retval[16];
3276 
3277  retval[ 0]=retval[ 1]=graymap[(((BIT15+BIT14) & up)>>10 )|(((BIT15+BIT14) & val)>>12 ) | (((BIT15+BIT14) & dn)>>14 )];
3278  retval[ 2]=retval[ 3]=graymap[(((BIT13+BIT12) & up)>> 8 )|(((BIT13+BIT12) & val)>>10 ) | (((BIT13+BIT12) & dn)>>12 )];
3279  retval[ 4]=retval[ 5]=graymap[(((BIT11+BIT10) & up)>> 6 )|(((BIT11+BIT10) & val)>> 8 ) | (((BIT11+BIT10) & dn)>>10 )];
3280  retval[ 6]=retval[ 7]=graymap[(((BIT9 +BIT8 ) & up)>> 4 )|(((BIT9 +BIT8 ) & val)>> 6 ) | (((BIT9 +BIT8 ) & dn)>> 8 )];
3281  retval[ 8]=retval[ 9]=graymap[(((BIT7 +BIT6 ) & up)>> 2 )|(((BIT7 +BIT6 ) & val)>> 4 ) | (((BIT7 +BIT6 ) & dn)>> 6 )];
3282  retval[10]=retval[11]=graymap[(((BIT5 +BIT4 ) & up)     )|(((BIT5 +BIT4 ) & val)>> 2 ) | (((BIT5 +BIT4 ) & dn)>> 4 )];
3283  retval[12]=retval[13]=graymap[(((BIT3 +BIT2 ) & up)<< 2 )|(((BIT3 +BIT2 ) & val)     ) | (((BIT3 +BIT2 ) & dn)>> 2 )];
3284  retval[14]=retval[15]=graymap[(((BIT1 +BIT0 ) & up)<< 4 )|(((BIT1 +BIT0 ) & val)<< 2 ) | (((BIT1 +BIT0 ) & dn)     )];
3285 
3286 }
3287 
3288 
RePaint_AAGray(void)3289 void LisaWin::RePaint_AAGray(void)
3290 {
3291    // vars for SETRGB16
3292    int updated=0;
3293    uint32 a1,a2,a3,a4,a5,xx;
3294    uint16 vup,vdn,val,vvu,vvd;
3295    uint16 high,medium,low;
3296    uint8  d;
3297 
3298    uint8 replacegray[16]; // ignore dumb compiler warning here!
3299    dirty_x_min=720; dirty_x_max=-1; dirty_y_min=384*3; dirty_y_max=-1;
3300 
3301 #ifdef USE_RAW_BITMAP_ACCESS
3302 
3303  int depth;
3304  int width;
3305  int height;
3306  int ox,oy;             // private to this - not member vars
3307 
3308 
3309 if (skins_on)
3310    {
3311     if (!my_skin) { replacegray[0]=0;  // useless statement to suppress dumb "unused" compiler warning
3312 	                return;}
3313 
3314     depth = my_skin->GetDepth();    width = my_skin->GetWidth();    height= my_skin->GetHeight();
3315     ox=screen_origin_x;    oy=screen_origin_y;
3316    }
3317 else
3318    {
3319     if (!my_lisabitmap) return;
3320 
3321     depth = my_lisabitmap->GetDepth();    width = my_lisabitmap->GetWidth();    height= my_lisabitmap->GetHeight();
3322     ox=0; oy=0;
3323    }
3324 
3325    typedef wxPixelData<wxBitmap,wxNativePixelFormat> PixelData;
3326    PixelData data(skins_on ? *my_skin:*my_lisabitmap);
3327    if (!data) return;
3328    PixelData::Iterator p(data);
3329    p.Reset(data);
3330    p.MoveTo(data,ox,oy);
3331    for ( int y = 0; y < effective_lisa_vid_size_y; ++y )   // effective_lisa_vid_size_y
3332    {
3333        PixelData::Iterator rowStart = p;              // save the x,y coordinates at the start of the line
3334 
3335 	   for ( int x = 0; x < effective_lisa_vid_size_x; )
3336 	       { SETRGB16_AAG(x,y,  {p.Red()=d; p.Green()=d; p.Blue()=(d+EXTRABLUE); ++p;} , {++p;} );}
3337 
3338 	   p.Red()=0; p.Green()=0; p.Blue()=0;
3339 
3340 
3341        p = rowStart; p.OffsetY(data, 1);              // restore the x,y coords from start of line, then increment y to do y++;
3342    }
3343 
3344 #else
3345 
3346   // Since we're working the slower way - with images, we need to rebuild the bitmap from the image.
3347   // to do this, we discard the old bitmap and recreate it from the display_image.  This is of course
3348   // slower, which is why we recommend the use of USE_RAW_BITMAP_ACCESS, but USE_RAW_BITMAP_ACCESS
3349   // might not work everywhere, so we give the option.
3350   if (skins_on)
3351   {
3352     if (!my_skin || !my_lisabitmap) return;
3353 
3354   //  int depth = my_skin->GetDepth();
3355   //  int width = my_skin->GetWidth();
3356   //  int height= my_skin->GetHeight();
3357 
3358  	if (!display_image)
3359          display_image= new wxImage(  my_lisabitmap->ConvertToImage());
3360 
3361 	for ( int y=0; y < effective_lisa_vid_size_y; y++ )
3362 	    {
3363 		    for ( int x=0; x < effective_lisa_vid_size_x;)
3364                 { SETRGB16_AAG(x,y,{display_image->SetRGB(x,y,d,d,d+EXTRABLUE); },{;}); }
3365 	    }
3366 
3367     delete my_lisabitmap;
3368 	my_lisabitmap=new wxBitmap(*display_image);
3369 	my_memDC->SelectObjectAsSource(*my_lisabitmap);
3370 
3371     e_dirty_x_min=dirty_x_min;                       // need to do these here so we can update just the rectangle we need.
3372     e_dirty_x_max=dirty_x_max;                       // it will be repeated again below, but so what, it's only 4 assignments
3373     e_dirty_y_min=dirty_y_min; //screen_y_map[dirty_y_min];         // and two lookups.
3374     e_dirty_y_max=dirty_y_max; //screen_y_map[dirty_y_max];
3375 
3376     if (updated)
3377        my_skinDC->Blit(screen_origin_x + e_dirty_x_min, screen_origin_y+e_dirty_y_min,     // target x,y
3378                        e_dirty_x_max-e_dirty_x_min+1,   e_dirty_y_max-e_dirty_y_min+1,     // size w,h
3379                        my_memDC, 0,0, wxCOPY, false);
3380 
3381     // we don't delete display_image since we can reuse it the next time around and save time
3382   }
3383   else  // skins are off
3384   {
3385 //    int depth = my_lisabitmap->GetDepth();
3386 //    int width = my_lisabitmap->GetWidth();
3387 //    int height= my_lisabitmap->GetHeight();
3388 
3389     if (!display_image)   display_image= new wxImage(my_lisabitmap->ConvertToImage());
3390 
3391 	for ( int yo = 0 , yi=0; yi < effective_lisa_vid_size_y; yo++,yi++ )
3392 	    {
3393 		   // note neither xi, nor xo are incremented as part of the for-loop header, this is because
3394 		   // the SETRGB16_AA macro expands to 16 iterations, and it increments xi on each iteration.
3395 		   // however, it doesn't do anything with xo, so xo++ is passed as a parameter.
3396 		   for ( int xo = 0, xi=0; xi < effective_lisa_vid_size_x;)
3397                { SETRGB16_AAG(xi,yi,{display_image->SetRGB(xo,yo,d,d,d+EXTRABLUE); xo++;},{xo++;});   }
3398 	    }
3399 
3400 	delete my_lisabitmap;
3401 	my_lisabitmap=new wxBitmap(*display_image);
3402 	my_memDC->SelectObjectAsSource(*my_lisabitmap);
3403   }
3404 #endif
3405 /////////////////////////////////////////////////////////////////////////
3406 
3407   e_dirty_x_min=dirty_x_min;                       // need to do these here so we can update just the rectangle we need.
3408   e_dirty_x_max=dirty_x_max;                       // it will be repeated again below, but so what, it's only 4 assignments
3409   e_dirty_y_min=dirty_y_min; //screen_y_map[dirty_y_min];         // and two lookups.
3410   e_dirty_y_max=dirty_y_max; //screen_y_map[dirty_y_max];
3411 
3412   if (updated)
3413   {
3414       memcpy(dirtyvidram,&lisaram[videolatchaddress],32768);
3415       repaintall |= REPAINT_INVALID_WINDOW | REPAINT_VIDEO_TO_SKIN;
3416 	  updated=0;
3417   }
3418 
3419 
3420 }
3421 
3422 
OnPaint(wxPaintEvent & event)3423 void LisaWin::OnPaint(wxPaintEvent &event )
3424 {
3425   if (!my_lisaframe) return; // not built yet!
3426   if (!my_lisawin)   return;
3427 
3428   if (!my_lisaframe->running)   repaintall |= REPAINT_INVALID_WINDOW;
3429   if ( my_alias==NULL || refresh_bytemap) ContrastChange();
3430 
3431   if ( my_memDC==NULL)       my_memDC     =new class wxMemoryDC;
3432   if ( my_lisabitmap==NULL)
3433   {
3434        my_lisabitmap=new class wxBitmap(effective_lisa_vid_size_x,effective_lisa_vid_size_y, DEPTH); //,my_lisaframe->depth);
3435        my_memDC->SelectObjectAsSource(*my_lisabitmap);
3436 	   my_memDC->SetBrush(FILLERBRUSH);      my_memDC->SetPen(FILLERPEN);
3437 	   my_memDC->DrawRectangle(0 ,   0,   effective_lisa_vid_size_x, effective_lisa_vid_size_y);
3438   	   if (!my_memDC->IsOk()) ALERT_LOG(0,"my_memDC is not ok.");
3439   	   if (!my_lisabitmap->IsOk()) ALERT_LOG(0,"my_lisabitmap is not ok.");
3440   }
3441 
3442   if ((dirtyscreen || videoramdirty) && (powerstate & POWER_ON_MASK) == POWER_ON)
3443                                         (my_lisawin->*RePainter)();  // whoever came up with this C++ syntax instead of the old C one was on crack!
3444 
3445   // from wx2.8 help
3446   wxRegionIterator upd(GetUpdateRegion()); // get the update rect list
3447 
3448   while (upd)
3449   {
3450 
3451     wxRect rect(upd.GetRect());
3452     wxRect display(screen_origin_x,screen_origin_y, effective_lisa_vid_size_x,effective_lisa_vid_size_y);
3453 
3454     // if this was an actual request to update the screen, then flag it as such.
3455     if (rect.Intersects(display))         repaintall |= REPAINT_INVALID_WINDOW | REPAINT_VIDEO_TO_SKIN;
3456 
3457     if ( skins_on) OnPaint_skins(   rect);
3458     else           OnPaint_skinless(rect);
3459 
3460     upd++;
3461   }
3462 
3463 
3464   dirtyscreen=0;
3465   videoramdirty=0;
3466  #ifdef __WXOSX__
3467   event.Skip(false);
3468  #endif
3469 }
3470 
OnPaint_skinless(wxRect & rect)3471 void LisaWin::OnPaint_skinless(wxRect &rect)
3472 {
3473    wxPaintDC dc(this);
3474    DoPrepareDC(dc);
3475 #ifdef __WXMACOSX__
3476    dc.SetBackgroundMode(wxTRANSPARENT); // OS X has a nasty habbit of erasing the background even though we skip the event!
3477 #endif
3478 
3479    int width, height, w_width, w_height;
3480    width=rect.GetWidth();              // junk assignment to suppress " warning: unused parameter 'rect'"
3481    height=rect.GetHeight();
3482 
3483    GetClientSize(&w_width,&w_height);
3484 
3485    correct_my_lisabitmap();  // hack/fix for linux
3486 
3487    ox=(w_width  - effective_lisa_vid_size_x)/2;
3488    oy=(w_height - effective_lisa_vid_size_y)/2;
3489    screen_origin_x=ox;  screen_origin_y=oy;
3490 
3491    if (my_lisaframe->running)
3492    {
3493        ex=w_width-ox; ey=w_height-oy;
3494 
3495        // draw a black border around the lisa display
3496        dc.SetBrush(*wxBLACK_BRUSH);      dc.SetPen(*wxBLACK_PEN);
3497        if (oy>1)         dc.DrawRectangle(0 ,   0,   w_width,oy    );   // top
3498        if (ey<w_height)  dc.DrawRectangle(0 ,  ey-2, w_width,w_height); // bottom
3499        if (ey>1)         dc.DrawRectangle(0 ,  oy,   ox,     ey    );   // center-left
3500        if (ex-1<w_width) dc.DrawRectangle(ex-1,oy,   w_width,ey    );   // center-right
3501 
3502        if (e_dirty_x_min>e_dirty_x_max || e_dirty_y_min>e_dirty_y_max)
3503           {
3504            e_dirty_x_min=0; e_dirty_x_max=lisa_vid_size_x;
3505            e_dirty_y_min=0; e_dirty_y_max=effective_lisa_vid_size_y;
3506           }
3507 
3508 
3509  	   dc.Blit(ox+e_dirty_x_min,                 oy+e_dirty_y_min,                                 // target x,y on window
3510 			      e_dirty_x_max-e_dirty_x_min,      e_dirty_y_max-e_dirty_y_min,     my_memDC,     // width, height, source DC
3511 				  e_dirty_x_min,                    e_dirty_y_min);                                // source x,y
3512 
3513        e_dirty_x_min=720; e_dirty_x_max=0; e_dirty_y_min=364*3; e_dirty_y_max=-1;                  // reset coordinates for next pass
3514    }
3515    else    // not running
3516    {
3517        dc.SetBrush(*wxBLACK_BRUSH);  dc.SetPen(*wxBLACK_PEN);
3518        dc.DrawRectangle(0 ,0,   width,height);
3519    }
3520 
3521    repaintall=0;
3522 }
3523 
3524 
OnPaint_skins(wxRect & rect)3525 void LisaWin::OnPaint_skins(wxRect &rect)
3526 {
3527 
3528    wxPaintDC dc(this);
3529    DoPrepareDC(dc);
3530 #ifdef __WXMACOSX__
3531    dc.SetBackgroundMode(wxTRANSPARENT); // OS X has a nasty habbit of erasing the background even though we skip the event!
3532 #endif
3533 
3534 
3535    correct_my_skin();
3536 
3537    // The first time we're in here, draw the skins.  The skins are cut in quarters because
3538    // some versions of wxWidgets can't handle such a large wxBitmap. :-(  Once we build the skin
3539    // we discard the images and set them to null, so this only runs once.
3540 
3541    if ((powerstate & POWER_NEEDS_REDRAW)==POWER_NEEDS_REDRAW && my_skin0)
3542    {
3543     int y=0;
3544 
3545     my_skinDC->Blit(0,y, my_skin0->GetWidth(),my_skin0->GetHeight(),my_skin0DC, 0,0 ,wxCOPY, false);   y+=my_skin0->GetHeight();
3546     my_skinDC->Blit(0,y, my_skin1->GetWidth(),my_skin1->GetHeight(),my_skin1DC, 0,0 ,wxCOPY, false);   y+=my_skin1->GetHeight();
3547     my_skinDC->Blit(0,y, my_skin2->GetWidth(),my_skin2->GetHeight(),my_skin2DC, 0,0 ,wxCOPY, false);   y+=my_skin2->GetHeight();
3548     my_skinDC->Blit(0,y, my_skin3->GetWidth(),my_skin3->GetHeight(),my_skin3DC, 0,0 ,wxCOPY, false); //y+=my_skin3->GetHeight();
3549 
3550 
3551     delete my_skin0;           my_skin0=NULL;
3552     delete my_skin1;           my_skin1=NULL;
3553     delete my_skin2;           my_skin2=NULL;
3554     delete my_skin3;           my_skin3=NULL;
3555 
3556     delete my_skin0DC;         my_skin0DC=NULL;
3557     delete my_skin1DC;         my_skin1DC=NULL;
3558     delete my_skin2DC;         my_skin2DC=NULL;
3559     delete my_skin3DC;         my_skin3DC=NULL;
3560    }
3561 
3562    if ((floppystate & FLOPPY_NEEDS_REDRAW) )
3563    {
3564      // The floppy's going to be redrawn so we to blit the floppy to the
3565      // skin, and then the window will need to be updated from the skin.
3566      repaintall |= REPAINT_INVALID_WINDOW | REPAINT_FLOPPY_TO_SKIN;
3567 
3568 
3569      switch(floppystate & FLOPPY_ANIM_MASK)
3570      {
3571 
3572         case 0:  my_skinDC->Blit(FLOPPY_LEFT, FLOPPY_TOP, my_floppy0->GetWidth(),my_floppy0->GetHeight(),my_floppy0DC,    0,0 ,wxCOPY, false); break;
3573         case 1:  my_skinDC->Blit(FLOPPY_LEFT, FLOPPY_TOP, my_floppy1->GetWidth(),my_floppy1->GetHeight(),my_floppy1DC,    0,0 ,wxCOPY, false); break;
3574         case 2:  my_skinDC->Blit(FLOPPY_LEFT, FLOPPY_TOP, my_floppy2->GetWidth(),my_floppy2->GetHeight(),my_floppy2DC,    0,0 ,wxCOPY, false); break;
3575         case 3:  my_skinDC->Blit(FLOPPY_LEFT, FLOPPY_TOP, my_floppy3->GetWidth(),my_floppy3->GetHeight(),my_floppy3DC,    0,0 ,wxCOPY, false); break;
3576        default:  my_skinDC->Blit(FLOPPY_LEFT, FLOPPY_TOP, my_floppy4->GetWidth(),my_floppy4->GetHeight(),my_floppy4DC,    0,0 ,wxCOPY, false);
3577 
3578      }
3579 
3580      floppystate &= FLOPPY_ANIMATING | FLOPPY_ANIM_MASK; //XXX Is this right?
3581     }
3582 
3583 
3584 
3585 
3586     if ((powerstate & POWER_NEEDS_REDRAW) )
3587     {
3588      // The power's going to be redrawn so we to blit the power to the
3589      // skin, and then the window will need to be updated from the skin.
3590      repaintall |= REPAINT_INVALID_WINDOW | REPAINT_POWER_TO_SKIN;
3591 
3592      if ((powerstate & POWER_ON_MASK) == POWER_ON)
3593         {
3594           my_skinDC->Blit(POWER_LEFT, POWER_TOP,  my_poweron->GetWidth(), my_poweron->GetHeight(), my_poweronDC, 0,0, wxCOPY, false);
3595 
3596           // These coordinates are a small rectangle around the powerlight
3597           if (powerstate & POWER_PUSHED)
3598              my_skinDC->Blit(1143-2,836-2, (1185-1143)+2  , (876-836)+2, my_poweronDC,  1143,(836-738), wxCOPY, false);
3599         }
3600      else
3601         {
3602           my_skinDC->Blit(POWER_LEFT, POWER_TOP,  my_poweroff->GetWidth(), my_poweroff->GetHeight(), my_poweroffDC, 0,0, wxCOPY, false);
3603 
3604           if (powerstate & POWER_PUSHED)
3605               my_skinDC->Blit(1143-2,836-2, (1185-1143)+2  , (876-836)+2, my_poweroffDC,  1143,(836-738), wxCOPY, false);
3606         }
3607 
3608      powerstate &= ~POWER_PUSHED;
3609     }
3610 
3611 
3612      ///////////////////////////////////////////////////////////////////
3613      int vbX,vbY;
3614      int ivbX,ivbY;
3615      int width,height;
3616 
3617      GetViewStart(&vbX,&vbY);           // convert scrollbar position into skin relative pixels
3618 
3619      ivbX=vbX; ivbY=vbY;
3620      vbX=vbX * (my_skin->GetWidth()/100);
3621      vbY=vbY * (my_skin->GetHeight()/100);
3622 
3623 	 vbX  +=rect.GetX()-1;
3624 	 vbY  +=rect.GetY()-1;
3625 	 height=rect.GetHeight()+1;
3626 	 width =rect.GetWidth()+1;
3627 
3628      width= MIN(width,my_skin->GetWidth()  );
3629      height=MIN(height,my_skin->GetHeight());
3630 	 vbX=MAX(vbX,0); vbY=MAX(vbY,0);
3631 
3632 
3633 	 dc.Blit(vbX,vbY, width, height, my_skinDC, vbX,vbY, wxCOPY, false);
3634 
3635      repaintall=0;
3636 }
3637 
OnErase(wxEraseEvent & event)3638 void LisaWin::OnErase(wxEraseEvent &event)
3639 {
3640 #ifdef __WXOSX__
3641 	event.GetDC()->SetBackground(*wxTRANSPARENT_BRUSH);
3642 	event.GetDC()->SetBackgroundMode(wxTRANSPARENT);
3643 	event.Skip();
3644 	event.StopPropagation();
3645 #endif
3646 }
3647 
3648 
black(void)3649 void black(void)
3650 {
3651   if (skins_on && my_skin!=NULL)
3652      {
3653 	   if (my_skinDC)
3654        {
3655         my_skinDC->SetBrush(FILLERBRUSH);   // these must be white, else linux drawing breaks
3656         my_skinDC->SetPen(FILLERPEN);       // these must be white, else linux drawing breaks
3657         my_skinDC->DrawRectangle(screen_origin_x,screen_origin_y, effective_lisa_vid_size_x,effective_lisa_vid_size_y);
3658        }
3659       }
3660   else
3661      {
3662 	   if (my_memDC)
3663 	   {
3664          my_memDC->SetBrush(FILLERBRUSH);   // these must be white, else linux drawing breaks
3665          my_memDC->SetPen(FILLERPEN);       // these must be white, else linux drawing breaks
3666          my_memDC->DrawRectangle(0,0,effective_lisa_vid_size_x+1,effective_lisa_vid_size_y);
3667        }
3668      }
3669 
3670 my_lisawin->Refresh();
3671 my_lisawin->Update();
3672 }
3673 
3674 
setstatusbar(char * text)3675 extern "C" void setstatusbar(char *text)
3676 {
3677 	wxString x=wxString(text, wxConvLocal, 2048); //wxSTRING_MAXLEN);
3678     my_lisaframe->SetStatusBarText(x);
3679 }
3680 
islisarunning(void)3681 extern "C" int islisarunning(void)
3682 {return     my_lisaframe->running;}
3683 
3684 
lightning(void)3685 void lightning(void)
3686 {
3687 
3688  if (!skins_on)
3689     {
3690         contrast=0xf;
3691         //contrastchange();
3692         black();
3693         ALERT_LOG(0,"Lightning skipped - skins off.");
3694         return;
3695     }
3696  static XTIMER lastclk;
3697 
3698  if (lastclk==cpu68k_clocks) {
3699                               ALERT_LOG(0,"skipping duplicate");
3700                               return; // got a duplicate due to screen refresh
3701                              }
3702  lastclk=cpu68k_clocks;
3703 
3704  // CAN YOU FEEL IT BUILDING
3705 
3706  // CAN YOU FEEL IT BUILDING
3707  black();
3708  // DEVASTATION IS ON THE WAY
3709 
3710  wxMilliSleep(300);
3711  my_poweroffclk->Play(wxSOUND_ASYNC);
3712 
3713  /* Draw the central flash */
3714  my_skinDC->SetPen(FILLERPEN);
3715  my_skinDC->SetBrush(FILLERBRUSH);
3716  my_skinDC->DrawRectangle(screen_origin_x + effective_lisa_vid_size_x/2 -24, screen_origin_y,
3717                           48, effective_lisa_vid_size_y);
3718 
3719  videoramdirty=0; my_lisawin->RefreshRect(wxRect(screen_origin_x + effective_lisa_vid_size_x/2 -24, screen_origin_y,
3720                           48, effective_lisa_vid_size_y),false);
3721 
3722  my_lisawin->Refresh(); my_lisawin->Update();
3723  wxMilliSleep(100);
3724 
3725  /* Blacken the screen */
3726  my_skinDC->SetPen(*wxBLACK_PEN);
3727  my_skinDC->SetBrush(*wxBLACK_BRUSH);
3728 
3729 
3730  for (int i=12; i>-1; i-=4)
3731  {
3732    // left
3733 
3734    my_skinDC->SetPen(*wxBLACK_PEN);
3735    my_skinDC->SetBrush(*wxBLACK_BRUSH);
3736 
3737    my_skinDC->DrawRectangle(screen_origin_x, screen_origin_y,
3738                             effective_lisa_vid_size_x/2 -i, effective_lisa_vid_size_y);
3739 
3740    // right
3741    my_skinDC->DrawRectangle(screen_origin_x + effective_lisa_vid_size_x/2 + i, screen_origin_y,
3742                             effective_lisa_vid_size_x/2 -i+1,
3743                             effective_lisa_vid_size_y);
3744 
3745    videoramdirty=0;
3746    my_lisawin->RefreshRect(wxRect(screen_origin_x, screen_origin_y,
3747                                   effective_lisa_vid_size_x,effective_lisa_vid_size_y),
3748                                   false);
3749    my_lisawin->Refresh(); my_lisawin->Update();
3750    wxMilliSleep(75);
3751  }
3752 
3753 
3754      my_lisawin->powerstate = POWER_NEEDS_REDRAW;
3755      my_lisawin->powerstate = POWER_NEEDS_REDRAW;     my_lisawin->dirtyscreen=1;     my_lisawin->repaintall|=1;
3756      my_lisawin->powerstate = POWER_OFF;
3757     contrast=0xf;
3758     contrastchange();
3759 
3760     my_lisawin->Refresh(); my_lisawin->Update();
3761 }
3762 
3763 int initialize_all_subsystems(void);
3764 
3765 
handle_powerbutton(void)3766 void handle_powerbutton(void)
3767 {
3768 
3769 //   ALERT_LOG(0,"Power Button Pressed.");
3770 
3771 
3772               if ((my_lisawin->powerstate & POWER_ON_MASK) == POWER_ON) // power is already on, send a power-key event instead
3773               {
3774                int i;
3775 
3776                setstatusbar("Sending power key event");
3777                presspowerswitch();                      // send keyboard event.
3778 
3779                if (running_lisa_os==LISA_OFFICE_RUNNING)
3780                   {
3781                     refresh_rate_used=5*REFRESHRATE;       // speed up contrast ramp by lowering the refresh rate
3782                     my_lisaframe->clockfactor=0;           // speed up shutdown to compensane for printing slowdown
3783                   }
3784                my_lisaconfig->Save(pConfig, floppy_ram);
3785 
3786                setstatusbar("Flushing any queued print jobs.");
3787                for (i=0; i<9; i++) iw_formfeed(i);
3788                //setstatusbar("Shutting down printers");
3789                //iw_shutdown();                             // this is too slow, so skip it
3790                setstatusbar("Waiting for Lisa to shut down...");
3791               }
3792               else
3793               {
3794 				  int ret;
3795 
3796 				  // 20071204 hack to fix windows bugs with RAWBITMAP
3797 				  #ifdef USE_RAW_BITMAP_ACCESS
3798 
3799 				    #ifdef __WXMSW__
3800 					if (skins_on) {turn_skins_off(); turn_skins_on();}
3801 					black();
3802 				    #endif
3803 
3804 				  #endif
3805 
3806                   ret=initialize_all_subsystems();
3807                   if (!ret)
3808                   {
3809                         my_lisawin->powerstate|= POWER_NEEDS_REDRAW | POWER_ON;
3810                         my_lisaframe->running=emulation_running;
3811                         my_lisaframe->runtime.Start(0);
3812 						my_lisaframe->lastcrtrefresh=0;
3813                   }
3814                   else
3815                        if (!romless) wxMessageBox(_T("Power on failed."), _T("Poweron Failed"), wxICON_INFORMATION | wxOK);
3816                   if (ret>1) EXIT(999,0,"Out of memory or other fatal error.");  // out of memory or other fatal error!
3817                   contrast=0;
3818 
3819                   presspowerswitch();                      // send keyboard event.
3820 
3821                   my_lisawin->dirtyscreen=1;
3822               }
3823 
3824         my_lisawin->dirtyscreen=1;
3825 
3826         save_global_prefs();
3827         my_lisaframe->UpdateProfileMenu();
3828 }
3829 
3830 
lisa_powered_off(void)3831 extern "C" void lisa_powered_off(void)
3832 {
3833    my_lisaframe->running=emulation_off;                // no longer running
3834    if ((my_lisawin->floppystate & FLOPPY_ANIM_MASK)!=FLOPPY_EMPTY)
3835    {
3836 	 eject_floppy_animation();
3837      my_lisaframe->Refresh(false,NULL);                // clean up display
3838      my_lisaframe->Update();
3839      my_lisaframe->Refresh(false,NULL);                // clean up display
3840      my_lisaframe->Update();
3841      my_lisaframe->Refresh(false,NULL);                // clean up display
3842      my_lisaframe->Update();
3843    }
3844 
3845    if (skins_on) lightning();					     // CRT lightning
3846    else black();
3847 
3848    unvars();					                     // reset global vars
3849    my_lisaconfig->Save(pConfig, floppy_ram);         // save PRAM, configuration
3850    fileMenu->Check(ID_RUN,false);		             // emulator no longer running
3851    my_lisaframe->runtime.Pause();                    // pause the stopwatch
3852 
3853    my_lisawin->powerstate= POWER_NEEDS_REDRAW | POWER_OFF;
3854    my_lisawin->Update();
3855 
3856    setstatusbar("The Lisa has powered off");         // status
3857    my_lisaframe->Refresh(false,NULL);                // clean up display
3858    my_lisaframe->Update();
3859 
3860    iw_enddocuments();
3861 }
3862 
lisa_rebooted(void)3863 extern "C" void lisa_rebooted(void)
3864 {
3865    setstatusbar("The Lisa is rebooting.");
3866    my_lisaconfig->Save(pConfig, floppy_ram);         // save PRAM, configuration
3867    unvars();                                         // reset global vars and all
3868    my_lisaframe->running=emulation_off;              // prevent init_all_subs from barking
3869    my_lisawin->powerstate = POWER_OFF;               // will be turned back on immediately
3870    handle_powerbutton();                             // back on we go.
3871 }
3872 
3873 
3874 
OnMouseMove(wxMouseEvent & event)3875 void LisaWin::OnMouseMove(wxMouseEvent &event)
3876 {
3877 
3878     //PrepareDC(dc);
3879     wxString str;
3880     int vbX,vbY;                     // scrollbar location
3881 
3882 	mousemoved++;
3883 
3884      // windows bug - crashes because it gets a mouse event before the window is ready.
3885 
3886      wxPoint pos = event.GetPosition();
3887 
3888      if (skins_on && my_skin==NULL) return;
3889      if (my_lisabitmap==NULL) return;
3890 
3891      GetViewStart(&vbX,&vbY);
3892     // convert scrollbar position into skin relative pixels
3893      if (skins_on && my_skin!=NULL)
3894         {
3895          vbX=vbX * (my_skin->GetWidth()/100);
3896          vbY=vbY * (my_skin->GetHeight()/100);
3897         }
3898      else
3899         {
3900          vbX=vbX * (my_lisabitmap->GetWidth()/100);
3901          vbY=vbY * (my_lisabitmap->GetHeight()/100);
3902         }
3903 
3904      pos.x+=vbX;
3905      pos.y+=vbY;
3906 
3907     long x= pos.x;
3908     long yy= pos.y;
3909 
3910     long y = doubley ? (yy>>1) : yy;
3911     long tempy;
3912 
3913     tempy=pos.y-screen_origin_y;
3914     if (tempy<0) tempy=0;
3915     if (tempy>500) tempy=499;
3916 
3917 
3918     y=screen_to_mouse[tempy];
3919 
3920     x=x-screen_origin_x;
3921 
3922 
3923     // power animation + button
3924 
3925 	if (skins_on)
3926 	{
3927 
3928       if (pos.x>1143 && pos.x<1185 && pos.y>836 && pos.y<876)
3929       {
3930        my_lisawin->powerstate &= POWER_ON;
3931 
3932         // unlike normal UI buttons, where the action happens when you let go of the mouse button,
3933         // this is as it should be, as the Lisa turns on when the power button is pushed in.
3934         if (event.LeftDown())    {  if (sound_effects_on) my_lisa_power_switch01->Play(wxSOUND_ASYNC);
3935                                     my_lisawin->powerstate |= POWER_NEEDS_REDRAW | POWER_PUSHED;
3936                                     handle_powerbutton();
3937 								    my_lisaframe->Refresh(false,NULL);                // clean up display
3938 								    my_lisaframe->Update();
3939 
3940                                  }
3941 
3942         if (event.LeftUp())      {
3943 	                                 if (sound_effects_on) my_lisa_power_switch02->Play(wxSOUND_ASYNC);
3944 	                                 my_lisawin->powerstate |= POWER_NEEDS_REDRAW;
3945 								     my_lisaframe->Refresh(false,NULL);                // clean up display
3946 								     my_lisaframe->Update();
3947 
3948                                  }
3949 
3950 
3951       }
3952 
3953       if    (my_floppy0!=NULL)
3954 	        {
3955 	         if	(pos.x>FLOPPY_LEFT && pos.x<FLOPPY_LEFT+my_floppy0->GetWidth() &&
3956     		     pos.y>FLOPPY_TOP  && pos.y<FLOPPY_TOP +my_floppy0->GetHeight()    )
3957 	             {
3958 	   	           if (event.LeftDown())   my_lisaframe->OnxFLOPPY();
3959   				   if (event.RightDown())  my_lisaframe->OnxNewFLOPPY();
3960 	             }
3961 			}
3962 	} // end if skins on
3963 
3964     if ( (y>0 && y<lisa_vid_size_y) && (x>=0 && x<lisa_vid_size_x) && my_lisaframe->running)
3965             {
3966                 static long lastup;
3967                 long now;                              // tee hee, the long now.
3968                 int lu=event.LeftUp();
3969                 now=my_lisaframe->runtime.Time();
3970 #if defined(__WXX11__) || defined(__WXGTK__) || defined(__WXOSX__)
3971                 if (hide_host_mouse) SetCursor(wxCURSOR_BLANK);
3972                 else                 SetCursor(*m_dot_cursor);
3973 #else
3974                 if (hide_host_mouse) SetCursor(wxCURSOR_BLANK);
3975                 else                 SetCursor(wxCURSOR_CROSS);
3976 #endif
3977                 add_mouse_event(x,y, lu ? -1:  (event.LeftDown() ? 1:0) );
3978 				seek_mouse_event();
3979 
3980                 // double click hack  - fixme BUG BUG BUG - fixme - well timing bug, will not be fixed if 32Mhz is allowed
3981                 if (lu)
3982                    {
3983                           if (now-lastup<1500)
3984                           {
3985                            add_mouse_event(x,y,  1);
3986                            add_mouse_event(x,y, -1);
3987                            add_mouse_event(x,y,  1);
3988                            add_mouse_event(x,y, -1);
3989                           }
3990 
3991                           lastup=now;
3992                    }
3993 
3994 
3995             }
3996     else
3997             my_lisawin->SetCursor(wxNullCursor);
3998 
3999     if (event.RightDown())   {videoramdirty=32768; my_lisaframe->Refresh(false,NULL);} // force screen refresh
4000 }
4001 
4002 
OnRun(wxCommandEvent & WXUNUSED (event))4003 void LisaEmFrame::OnRun(wxCommandEvent& WXUNUSED(event))
4004 {
4005     if (my_lisaframe->running==emulation_off)    {handle_powerbutton(); return;                 }
4006     if (my_lisaframe->running==emulation_paused) {my_lisaframe->running=emulation_running;      }
4007 
4008     fileMenu->Check(ID_RUN,  true);
4009 }
4010 
4011 
pause_run(void)4012 extern "C" void pause_run(void)
4013 {
4014    if (my_lisaframe->running==emulation_off) return;
4015 
4016    if (my_lisaframe->running==emulation_running)
4017    {
4018      my_lisaframe->runtime.Pause();
4019      my_lisaframe->running=emulation_paused;
4020      return;
4021    }
4022 }
4023 
resume_run(void)4024 extern "C" void resume_run(void)
4025 {
4026    if (my_lisaframe->running==emulation_off) return;
4027 
4028    if (my_lisaframe->running==emulation_paused)
4029    {
4030      my_lisaframe->runtime.Resume();
4031      my_lisaframe->running=emulation_running;
4032      return;
4033    }
4034 }
4035 
4036 
OnPause(wxCommandEvent & WXUNUSED (event))4037 void LisaEmFrame::OnPause(wxCommandEvent& WXUNUSED(event))
4038 {
4039     if (my_lisaframe->running==emulation_off)      {                                                return;}
4040     if (my_lisaframe->running==emulation_running)  {pause_run();   fileMenu->Check(ID_PAUSE,true);  return;}
4041     if (my_lisaframe->running==emulation_paused)   {resume_run();  fileMenu->Check(ID_PAUSE,false); return;}
4042 }
4043 
4044 
OnAbout(wxCommandEvent & WXUNUSED (event))4045 void LisaEmFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
4046 {
4047     wxAboutDialogInfo info;
4048     info.SetName(_T("LisaEm"));
4049 
4050 #ifdef VERSION
4051     info.SetVersion(_T(VERSION));
4052 #else
4053     info.SetVersion(_T("1.x.x Unknown"));
4054 #endif
4055 
4056 	info.SetDescription(_T("The first fully functional Apple Lisa emulator."));
4057     info.SetCopyright(_T("\xa9 2007 Ray Arachelian"));
4058 	info.SetWebSite(_T("http://lisaem.sunder.net"));
4059     info.AddDeveloper(_T("Ray Arachelian - Emulator"));
4060 	info.AddDeveloper(_T("Brian Foley - OS X UI"));
4061 	info.AddDeveloper(_T("James Ponder - 68K core.\n"));
4062 #ifdef LICENSE
4063 	info.SetLicense(_T(LICENSE));
4064 #endif
4065 
4066 #ifdef BUILTBY
4067 	info.AddDeveloper(_T("\n\n" BUILTBY));
4068 #endif
4069 
4070 	wxAboutBox(info);
4071 }
4072 #ifdef __WXOSX__
OnQuit(wxCommandEvent & WXUNUSED (event))4073 void LisaEmFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
4074 #else
4075 void LisaEmApp::OnQuit(wxCommandEvent& WXUNUSED(event))
4076 #endif
4077 {
4078     if (NULL!=my_lisabitmap          )             {delete my_lisabitmap          ;   my_lisabitmap=NULL;           }
4079     if (NULL!=my_memDC               )             {delete my_memDC               ;   my_memDC=NULL;                }
4080 
4081     if (NULL!=my_lisa_sound          )             {delete my_lisa_sound          ;   my_lisa_sound=NULL;           }
4082 
4083     if (NULL!=my_floppy_eject        )             {delete my_floppy_eject        ;   my_floppy_eject=NULL;         }
4084     if (NULL!=my_floppy_insert       )             {delete my_floppy_insert       ;   my_floppy_insert=NULL;        }
4085     if (NULL!=my_floppy_motor1       )             {delete my_floppy_motor1       ;   my_floppy_motor1=NULL;        }
4086     if (NULL!=my_floppy_motor2       )             {delete my_floppy_motor2       ;   my_floppy_motor2=NULL;        }
4087     if (NULL!=my_lisa_power_switch01 )             {delete my_lisa_power_switch01 ;   my_lisa_power_switch01=NULL;  }
4088     if (NULL!=my_lisa_power_switch02 )             {delete my_lisa_power_switch02 ;   my_lisa_power_switch02=NULL;  }
4089     if (NULL!=my_poweroffclk         )             {delete my_poweroffclk         ;   my_poweroffclk=NULL;          }
4090     if (NULL!=my_bytemap)                          {delete my_bytemap;     my_bytemap=NULL; }
4091     if (NULL!=my_alias  )                          {delete my_alias  ;     my_alias  =NULL; }
4092 
4093     if (NULL!=my_skin   )                          {delete my_skin   ;     my_skin   =NULL; }
4094     if (NULL!=my_skin0  )                          {delete my_skin0  ;     my_skin   =NULL; }
4095     if (NULL!=my_skin1  )                          {delete my_skin1  ;     my_skin   =NULL; }
4096     if (NULL!=my_skin2  )                          {delete my_skin2  ;     my_skin   =NULL; }
4097     if (NULL!=my_skin3  )                          {delete my_skin3  ;     my_skin   =NULL; }
4098 
4099 
4100 
4101     if (NULL!=my_floppy0)                          {delete my_floppy0;     my_floppy0=NULL; }
4102     if (NULL!=my_floppy1)                          {delete my_floppy1;     my_floppy1=NULL; }
4103     if (NULL!=my_floppy2)                          {delete my_floppy2;     my_floppy2=NULL; }
4104     if (NULL!=my_floppy3)                          {delete my_floppy3;     my_floppy3=NULL; }
4105     if (NULL!=my_floppy4)                          {delete my_floppy4;     my_floppy4=NULL; }
4106 
4107     if (NULL!=my_poweron   )                       {delete my_poweron   ;  my_poweron   =NULL; }
4108     if (NULL!=my_poweroff  )                       {delete my_poweroff  ;  my_poweroff  =NULL; }
4109 
4110     if (NULL!=my_bytemapDC )                       {delete my_bytemapDC ;  my_bytemapDC =NULL; }
4111     if (NULL!=my_aliasDC   )                       {delete my_aliasDC   ;  my_aliasDC   =NULL; }
4112 
4113     if (NULL!=my_skinDC    )                       {delete my_skinDC    ;  my_skinDC    =NULL; }
4114     if (NULL!=my_floppy0DC )                       {delete my_floppy0DC ;  my_floppy0DC =NULL; }
4115     if (NULL!=my_floppy1DC )                       {delete my_floppy1DC ;  my_floppy1DC =NULL; }
4116     if (NULL!=my_floppy2DC )                       {delete my_floppy2DC ;  my_floppy2DC =NULL; }
4117     if (NULL!=my_floppy3DC )                       {delete my_floppy3DC ;  my_floppy3DC =NULL; }
4118     if (NULL!=my_floppy4DC )                       {delete my_floppy4DC ;  my_floppy4DC =NULL; }
4119 
4120     if (NULL!=my_poweronDC )                       {delete my_poweronDC ;  my_poweronDC =NULL; }
4121     if (NULL!=my_poweroffDC)                       {delete my_poweroffDC;  my_poweroffDC=NULL; }
4122 
4123 #ifdef __WXOSX__
4124      my_lisaframe->m_emulation_timer->Stop();  // stop the timer
4125   	 wxMilliSleep(emulation_time*2);	       // ensure that any pending timer events are allowed to finish
4126 	 delete my_lisaframe->m_emulation_timer;   // delete the timer
4127      if (my_LisaConfigFrame) {delete my_LisaConfigFrame; my_LisaConfigFrame=NULL;}  // close any ConfigFrame
4128 	 Close();                                  // and bye bye we go.
4129 #else
4130      my_lisaframe->m_emulation_timer->Stop();  // stop the timer
4131      wxMilliSleep(750);
4132      delete my_lisaframe->m_emulation_timer;
4133  	 wxMilliSleep(250);
4134      delete my_lisaframe;
4135      wxExit();
4136 #endif
4137 }
4138 
OnLisaWeb(wxCommandEvent & WXUNUSED (event))4139 void LisaEmFrame::OnLisaWeb(wxCommandEvent& WXUNUSED(event)) {::wxLaunchDefaultBrowser(_T("http://lisaem.sunder.net"));}
OnLisaFaq(wxCommandEvent & WXUNUSED (event))4140 void LisaEmFrame::OnLisaFaq(wxCommandEvent& WXUNUSED(event)) {::wxLaunchDefaultBrowser(_T("http://lisafaq.sunder.net"));}
4141 
4142 
4143 
4144 
OnConfig(wxCommandEvent & WXUNUSED (event))4145 void LisaEmFrame::OnConfig(wxCommandEvent& WXUNUSED(event))
4146 {
4147           if (my_LisaConfigFrame) {delete my_LisaConfigFrame; my_LisaConfigFrame=NULL;}
4148 
4149           if (!my_LisaConfigFrame)    my_LisaConfigFrame=new LisaConfigFrame( wxT("Preferences"), my_lisaconfig);
4150           #if defined(__WXMOTIF__)
4151           int x, y;
4152 
4153           GetSize(&x, &y);
4154           x+=WINXDIFF; y+=WINYDIFF;
4155           SetSize(wxDefaultCoord, wxDefaultCoord,x,y);
4156           #endif
4157 
4158           my_LisaConfigFrame->Show();
4159 
4160 }
4161 
OnOpen(wxCommandEvent & WXUNUSED (event))4162 void LisaEmFrame::OnOpen(wxCommandEvent& WXUNUSED(event))
4163 {
4164        wxString openfile;
4165        wxFileDialog open(this,                  wxT("Open LisaEm Preferences:"),
4166                                                 wxEmptyString,
4167                                                 wxEmptyString,
4168                                                 wxT("LisaEm Preferences (*.lisaem)|*.lisaem|All (*.*)|*.*"),
4169                                                 (long int)wxFD_OPEN,wxDefaultPosition);
4170 
4171        if (open.ShowModal()==wxID_OK)           openfile=open.GetPath();
4172        else return;
4173 
4174 
4175        if (pConfig) {pConfig->Flush();  delete pConfig; pConfig=NULL;}
4176        if (my_LisaConfigFrame) {delete my_LisaConfigFrame; my_LisaConfigFrame=NULL;}
4177 
4178        pConfig=new wxFileConfig(_T("LisaEm"),
4179                               _T("sunder.NET"),
4180                                 (openfile),     //local
4181                                 (openfile),     //global
4182                               wxCONFIG_USE_LOCAL_FILE,
4183                               wxConvAuto() );   // or wxConvUTF8
4184 
4185       pConfig->Get(true);
4186       if (my_lisaconfig) delete my_lisaconfig;
4187       my_lisaconfig = new LisaConfig();
4188       my_lisaconfig->Load(pConfig, floppy_ram);// load it in
4189 
4190 
4191 
4192 
4193 
4194       myconfigfile=openfile;  // update global file to point to new config
4195       save_global_prefs();    // and save them.
4196 }
4197 
OnSaveAs(wxCommandEvent & WXUNUSED (event))4198 void LisaEmFrame::OnSaveAs(wxCommandEvent& WXUNUSED(event))
4199 {
4200        wxString savefile;
4201 
4202 	   wxFileName prefs=wxFileName(myconfigfile);
4203 	   wxString justTheFilename=prefs.GetFullName();
4204  	   wxString justTheDir=prefs.GetPath(wxPATH_GET_VOLUME|wxPATH_GET_SEPARATOR,wxPATH_NATIVE);
4205 
4206 
4207        wxFileDialog open(this,                  wxT("Save LisaEm Preferences As:"),
4208                                                 justTheDir,  // path
4209                                                 justTheFilename,  // prefs file name
4210                                                 wxT("LisaEm Preferences (*.lisaem)|*.lisaem|All (*.*)|*.*"),
4211                                                 (long int)wxFD_SAVE,wxDefaultPosition
4212                         );
4213 
4214        if (open.ShowModal()==wxID_OK)           savefile=open.GetPath();
4215        else return;
4216 
4217        wxFileOutputStream out(savefile);
4218 
4219        if (pConfig->Save(out,wxConvUTF8) )
4220           {
4221             myconfigfile=savefile;
4222             save_global_prefs();
4223           }
4224 }
4225 
4226 
OnDebugger(wxCommandEvent & WXUNUSED (event))4227 void LisaEmFrame::OnDebugger(wxCommandEvent& WXUNUSED(event))            {}
4228 
4229 
4230 
OnPOWERKEY(wxCommandEvent & WXUNUSED (event))4231 void LisaEmFrame::OnPOWERKEY(wxCommandEvent& WXUNUSED(event))            {fileMenu->Check(ID_RUN,true); handle_powerbutton();}
4232 
4233 
OnAPPLEPOWERKEY(wxCommandEvent & WXUNUSED (event))4234 void LisaEmFrame::OnAPPLEPOWERKEY(wxCommandEvent& WXUNUSED(event))
4235         {
4236             send_cops_keycode(KEYCODE_COMMAND|KEY_DOWN);
4237             handle_powerbutton();
4238             send_cops_keycode(KEYCODE_COMMAND|KEY_UP);
4239         }
4240 
OnTraceLog(wxCommandEvent & WXUNUSED (event))4241 void LisaEmFrame::OnTraceLog(wxCommandEvent& WXUNUSED(event))
4242      {
4243       debug_log_enabled=!debug_log_enabled;
4244       if (debug_log_enabled) debug_on("user enabled");
4245       else                   debug_off();
4246 
4247       ALERT_LOG(0,"Debug has been turned %s",debug_log_enabled?"on":"off");
4248      }
4249 
OnKEY_APL_DOT(wxCommandEvent & WXUNUSED (event))4250 void LisaEmFrame::OnKEY_APL_DOT(wxCommandEvent& WXUNUSED(event))         {apple_dot();}
OnKEY_APL_S(wxCommandEvent & WXUNUSED (event))4251 void LisaEmFrame::OnKEY_APL_S(wxCommandEvent& WXUNUSED(event))           {apple_S();}
OnKEY_APL_ENTER(wxCommandEvent & WXUNUSED (event))4252 void LisaEmFrame::OnKEY_APL_ENTER(wxCommandEvent& WXUNUSED(event))       {apple_enter();}
OnKEY_APL_RENTER(wxCommandEvent & WXUNUSED (event))4253 void LisaEmFrame::OnKEY_APL_RENTER(wxCommandEvent& WXUNUSED(event))      {apple_renter();}
OnKEY_APL_1(wxCommandEvent & WXUNUSED (event))4254 void LisaEmFrame::OnKEY_APL_1(wxCommandEvent& WXUNUSED(event))           {apple_1();}
OnKEY_APL_2(wxCommandEvent & WXUNUSED (event))4255 void LisaEmFrame::OnKEY_APL_2(wxCommandEvent& WXUNUSED(event))           {apple_2();}
OnKEY_APL_3(wxCommandEvent & WXUNUSED (event))4256 void LisaEmFrame::OnKEY_APL_3(wxCommandEvent& WXUNUSED(event))           {apple_3();}
4257 
OnKEY_OPT_0(wxCommandEvent & WXUNUSED (event))4258 void LisaEmFrame::OnKEY_OPT_0(wxCommandEvent& WXUNUSED(event))           {shift_option_0();}
OnKEY_OPT_4(wxCommandEvent & WXUNUSED (event))4259 void LisaEmFrame::OnKEY_OPT_4(wxCommandEvent& WXUNUSED(event))           {shift_option_4();}
OnKEY_OPT_7(wxCommandEvent & WXUNUSED (event))4260 void LisaEmFrame::OnKEY_OPT_7(wxCommandEvent& WXUNUSED(event))           {shift_option_7();}
OnKEY_NMI(wxCommandEvent & WXUNUSED (event))4261 void LisaEmFrame::OnKEY_NMI(wxCommandEvent& WXUNUSED(event))             {send_nmi_key();}
OnKEY_RESET(wxCommandEvent & WXUNUSED (event))4262 void LisaEmFrame::OnKEY_RESET(wxCommandEvent& WXUNUSED(event))
4263 {
4264 	if (!running)
4265 	{
4266 		wxMessageBox(wxT("The Lisa isn't powered.  Pressing RESET now won't do anything interesting."),
4267 					 wxT("Lisa isn't powered on"), wxICON_INFORMATION | wxOK);
4268 		return;
4269 	}
4270 
4271    if (yesnomessagebox("This will reboot the Lisa, but may cause file system corruption",
4272 					   "Really RESET the Lisa?")==0) return;
4273 
4274    lisa_rebooted();
4275 }
4276 
4277 // display a floating keyboard and allow edits.
OnKEYBOARD(wxCommandEvent & WXUNUSED (event))4278 void LisaEmFrame::OnKEYBOARD(wxCommandEvent& WXUNUSED(event))  {}
4279 
4280 
4281 
4282 
OnASCIIKB(wxCommandEvent & WXUNUSED (event))4283 void LisaEmFrame::OnASCIIKB(wxCommandEvent& WXUNUSED(event))   {asciikeyboard= 1; save_global_prefs();}
OnRAWKB(wxCommandEvent & WXUNUSED (event))4284 void LisaEmFrame::OnRAWKB(wxCommandEvent& WXUNUSED(event))     {asciikeyboard= 0; save_global_prefs();}
OnRAWKBBUF(wxCommandEvent & WXUNUSED (event))4285 void LisaEmFrame::OnRAWKBBUF(wxCommandEvent& WXUNUSED(event))  {asciikeyboard=-1; save_global_prefs();}
4286 
4287 /* Make sure only one of the Throttle menu items is checked at any time. */
updateThrottleMenus(float throttle)4288 void updateThrottleMenus(float throttle)
4289 {
4290     if (!my_lisaframe) return;
4291     if (!throttleMenu) return;
4292 
4293     my_lisaframe->reset_throttle_clock();
4294 
4295     throttleMenu->Check(ID_THROTTLE5,   throttle ==  5.0);
4296     throttleMenu->Check(ID_THROTTLE8,   throttle ==  8.0);
4297     throttleMenu->Check(ID_THROTTLE10,  throttle == 10.0);
4298     throttleMenu->Check(ID_THROTTLE12,  throttle == 12.0);
4299     throttleMenu->Check(ID_THROTTLE16,  throttle == 16.0);
4300     throttleMenu->Check(ID_THROTTLE32,  throttle == 32.0);
4301 //    throttleMenu->Check(ID_THROTTLEX,   throttle == 10000000);
4302 
4303 	throttleMenu->Check(ID_ET100_75,    emulation_time==100 && emulation_tick==75);
4304 	throttleMenu->Check(ID_ET50_30,     emulation_time== 50 && emulation_tick==30);
4305 	throttleMenu->Check(ID_ET40_25,     emulation_time== 40 && emulation_tick==25);
4306 	throttleMenu->Check(ID_ET30_20,     emulation_time== 30 && emulation_tick==20);
4307 
4308 
4309     #ifdef TIE_VIA_TIMER_TO_HOST
4310     via_throttle_factor=throttle/5.0;
4311     #endif
4312 }
4313 
4314 
4315 
4316 // This is necessary since if we change the throttle, the OnIdle
4317 // execution loop needs a new reference point, else it will try
4318 // to adjust the runtime from power on which will not work.
reset_throttle_clock(void)4319 void LisaEmFrame::reset_throttle_clock(void)
4320 {
4321    cpu68k_reference=cpu68k_clocks;
4322    last_runtime_sample=0;
4323    lastcrtrefresh=0;
4324    runtime.Start(0);
4325    if    (throttle  ==10000000)
4326           clockfactor=0;
4327    else   clockfactor=1.0/(throttle*1000.0);
4328    cycles_wanted=(XTIMER)(float)(emulation_time/clockfactor);
4329 }
4330 
4331 
OnET100_75(wxCommandEvent & WXUNUSED (event))4332 void LisaEmFrame::OnET100_75(wxCommandEvent& WXUNUSED(event))  {emulation_time=100; emulation_tick=75; reset_throttle_clock(); save_global_prefs();}
OnET50_30(wxCommandEvent & WXUNUSED (event))4333 void LisaEmFrame::OnET50_30(wxCommandEvent& WXUNUSED(event))   {emulation_time= 50; emulation_tick=30; reset_throttle_clock(); save_global_prefs();}
OnET40_25(wxCommandEvent & WXUNUSED (event))4334 void LisaEmFrame::OnET40_25(wxCommandEvent& WXUNUSED(event))   {emulation_time= 40; emulation_tick=25; reset_throttle_clock(); save_global_prefs();}
OnET30_20(wxCommandEvent & WXUNUSED (event))4335 void LisaEmFrame::OnET30_20(wxCommandEvent& WXUNUSED(event))   {emulation_time= 30; emulation_tick=20; reset_throttle_clock(); save_global_prefs();}
4336 
4337 
OnThrottle5(wxCommandEvent & WXUNUSED (event))4338 void LisaEmFrame::OnThrottle5(wxCommandEvent& WXUNUSED(event))
4339 {
4340     throttle = 5;
4341     reset_throttle_clock();
4342     save_global_prefs();
4343 }
4344 
OnThrottle8(wxCommandEvent & WXUNUSED (event))4345 void LisaEmFrame::OnThrottle8(wxCommandEvent& WXUNUSED(event))
4346 {
4347     throttle = 8;
4348     reset_throttle_clock();
4349     save_global_prefs();
4350 }
4351 
OnThrottle10(wxCommandEvent & WXUNUSED (event))4352 void LisaEmFrame::OnThrottle10(wxCommandEvent& WXUNUSED(event))
4353 {
4354     throttle = 10;
4355     reset_throttle_clock();
4356     save_global_prefs();
4357 }
4358 
OnThrottle12(wxCommandEvent & WXUNUSED (event))4359 void LisaEmFrame::OnThrottle12(wxCommandEvent& WXUNUSED(event))
4360 {
4361     throttle = 12;
4362     reset_throttle_clock();
4363     save_global_prefs();
4364 }
OnThrottle16(wxCommandEvent & WXUNUSED (event))4365 void LisaEmFrame::OnThrottle16(wxCommandEvent& WXUNUSED(event))
4366 {
4367     throttle = 16;
4368     reset_throttle_clock();
4369     save_global_prefs();
4370 }
4371 
OnThrottle32(wxCommandEvent & WXUNUSED (event))4372 void LisaEmFrame::OnThrottle32(wxCommandEvent& WXUNUSED(event))
4373 {
4374     throttle=32;
4375     reset_throttle_clock();
4376     save_global_prefs();
4377 }
4378 
OnThrottleX(wxCommandEvent & WXUNUSED (event))4379 void LisaEmFrame::OnThrottleX(wxCommandEvent& WXUNUSED(event))
4380 {
4381     throttle=10000000;
4382     reset_throttle_clock();
4383     save_global_prefs();
4384 }
4385 
4386 
4387 
4388 
messagebox(char * s,char * t)4389 extern "C" void messagebox(char *s, char *t)  // messagebox string of text, title
4390            {
4391            	 wxString text =wxString(s, wxConvLocal, 2048); //wxSTRING_MAXLEN);
4392  			 wxString title=wxString(t, wxConvLocal, 2048); //wxSTRING_MAXLEN);
4393              wxMessageBox(text,title, wxICON_INFORMATION | wxOK);
4394            }
4395 
yesnomessagebox(char * s,char * t)4396 extern "C" int yesnomessagebox(char *s, char *t)  // messagebox string of text, title
4397            {
4398            	 wxString text =wxString(s, wxConvLocal, 2048); //wxSTRING_MAXLEN);
4399  			 wxString title=wxString(t, wxConvLocal, 2048); //wxSTRING_MAXLEN);
4400              wxMessageDialog w(my_lisawin,text,title, wxICON_QUESTION  | wxYES_NO |wxNO_DEFAULT,wxDefaultPosition );
4401              if (w.ShowModal()==wxID_YES) return 1;
4402              return 0;
4403            }
4404 
4405 
4406 
4407 
4408 
UpdateProfileMenu(void)4409 void LisaEmFrame::UpdateProfileMenu(void)
4410 {
4411   if (!profileMenu)   return;
4412   if (!my_lisaconfig) return;
4413   // s=paralell port, 3=s1h, 4=s1l, 5=s2h,6=s2l,7=s3h,8=s3l
4414 
4415   profileMenu->Check(ID_PROFILEPWR,     (IS_PARALLEL_PORT_ENABLED(2) && !my_lisaconfig->parallel.IsSameAs(_T("NOTHING"), false)  ));
4416 
4417   profileMenu->Check(ID_PROFILE_S1U,    (IS_PARALLEL_PORT_ENABLED(3) && (my_lisaconfig->slot1.IsSameAs(_T("dualparallel"),false)) && !my_lisaconfig->s1h.IsSameAs(_T("NOTHING"), false)  ));
4418   profileMenu->Check(ID_PROFILE_S1L,    (IS_PARALLEL_PORT_ENABLED(4) && (my_lisaconfig->slot1.IsSameAs(_T("dualparallel"),false)) && !my_lisaconfig->s1l.IsSameAs(_T("NOTHING"), false)  ));
4419   profileMenu->Check(ID_PROFILE_S2U,    (IS_PARALLEL_PORT_ENABLED(5) && (my_lisaconfig->slot2.IsSameAs(_T("dualparallel"),false)) && !my_lisaconfig->s2h.IsSameAs(_T("NOTHING"), false)  ));
4420   profileMenu->Check(ID_PROFILE_S2L,    (IS_PARALLEL_PORT_ENABLED(6) && (my_lisaconfig->slot2.IsSameAs(_T("dualparallel"),false)) && !my_lisaconfig->s2l.IsSameAs(_T("NOTHING"), false)  ));
4421   profileMenu->Check(ID_PROFILE_S3U,    (IS_PARALLEL_PORT_ENABLED(7) && (my_lisaconfig->slot3.IsSameAs(_T("dualparallel"),false)) && !my_lisaconfig->s3h.IsSameAs(_T("NOTHING"), false)  ));
4422   profileMenu->Check(ID_PROFILE_S3L,    (IS_PARALLEL_PORT_ENABLED(8) && (my_lisaconfig->slot3.IsSameAs(_T("dualparallel"),false)) && !my_lisaconfig->s3l.IsSameAs(_T("NOTHING"), false)  ));
4423 
4424   profileMenu->Enable(ID_PROFILEPWR,( !my_lisaconfig->parallel.IsSameAs(_T("NOTHING"), false) ));
4425   if ( my_lisaconfig->parallel.IsSameAs(_T("PROFILE"), false) )
4426      profileMenu->SetLabel(ID_PROFILEPWR,wxT("Power ProFile Parallel Port"));
4427   else
4428      profileMenu->SetLabel(ID_PROFILEPWR,wxT("Power ADMP on Parallel Port"));
4429 
4430 // GLOBAL(int,via_port_idx_bits[],{0, 2,1, 4,3, 6,5});
4431                               //2, 4,3, 6,5, 8,7
4432 
4433   if (my_lisaconfig->slot1.IsSameAs(_T("dualparallel"),false))
4434   {
4435     if (my_lisaconfig->s1h.IsSameAs(_T("PROFILE"), false)) profileMenu->SetLabel(ID_PROFILE_S1U,wxT("Power ProFile on Slot 1 Upper Port"));
4436     if (my_lisaconfig->s1l.IsSameAs(_T("PROFILE"), false)) profileMenu->SetLabel(ID_PROFILE_S1L,wxT("Power ProFile on Slot 1 Lower Port"));
4437 
4438     if (my_lisaconfig->s1h.IsSameAs(_T("ADMP"), false)) profileMenu->SetLabel(ID_PROFILE_S1U,wxT("Power ADMP on Slot 1 Upper Port"));
4439     if (my_lisaconfig->s1l.IsSameAs(_T("ADMP"), false)) profileMenu->SetLabel(ID_PROFILE_S1L,wxT("Power ADMP on Slot 1 Lower Port"));
4440 
4441     if (my_lisaconfig->s1h.IsSameAs(_T("NOTHING"), false)) profileMenu->SetLabel(ID_PROFILE_S1U,wxT("Nothing on Slot 1 Upper Port"));
4442     if (my_lisaconfig->s1l.IsSameAs(_T("NOTHING"), false)) profileMenu->SetLabel(ID_PROFILE_S1L,wxT("Nothing on Slot 1 Lower Port"));
4443 
4444 
4445 	profileMenu->Enable(ID_PROFILE_S1U,( !my_lisaconfig->s1h.IsSameAs(_T("NOTHING"), false)) );
4446 	profileMenu->Enable(ID_PROFILE_S1L,( !my_lisaconfig->s1l.IsSameAs(_T("NOTHING"), false)) );
4447   }
4448   else
4449   {
4450 	profileMenu->Enable(ID_PROFILE_S1U,false );
4451 	profileMenu->Enable(ID_PROFILE_S1L,false );
4452 	profileMenu->SetLabel(ID_PROFILE_S1U,_T("No Card"));
4453 	profileMenu->SetLabel(ID_PROFILE_S1L,_T("No Card"));
4454   }
4455 
4456 
4457   if (my_lisaconfig->slot2.IsSameAs(_T("dualparallel"),false))
4458   {
4459     if (my_lisaconfig->s2h.IsSameAs(_T("PROFILE"), false)) profileMenu->SetLabel(ID_PROFILE_S2U,wxT("Power ProFile on Slot 2 Upper Port"));
4460     if (my_lisaconfig->s2l.IsSameAs(_T("PROFILE"), false)) profileMenu->SetLabel(ID_PROFILE_S2L,wxT("Power ProFile on Slot 2 Lower Port"));
4461 
4462     if (my_lisaconfig->s2h.IsSameAs(_T("ADMP"), false)) profileMenu->SetLabel(ID_PROFILE_S2U,wxT("Power ADMP on Slot 2 Upper Port"));
4463     if (my_lisaconfig->s2l.IsSameAs(_T("ADMP"), false)) profileMenu->SetLabel(ID_PROFILE_S2L,wxT("Power ADMP on Slot 2 Lower Port"));
4464 
4465     if (my_lisaconfig->s2h.IsSameAs(_T("NOTHING"), false)) profileMenu->SetLabel(ID_PROFILE_S2U,wxT("Nothing on Slot 2 Upper Port"));
4466     if (my_lisaconfig->s2l.IsSameAs(_T("NOTHING"), false)) profileMenu->SetLabel(ID_PROFILE_S2L,wxT("Nothing on Slot 2 Lower Port"));
4467 
4468 
4469 	profileMenu->Enable(ID_PROFILE_S2U,( !my_lisaconfig->s2h.IsSameAs(_T("NOTHING"), false)) );
4470 	profileMenu->Enable(ID_PROFILE_S2L,( !my_lisaconfig->s2l.IsSameAs(_T("NOTHING"), false)) );
4471   }
4472   else
4473   {
4474 	profileMenu->Enable(ID_PROFILE_S2U,false );
4475 	profileMenu->Enable(ID_PROFILE_S2L,false );
4476 	profileMenu->SetLabel(ID_PROFILE_S2U,_T("No Card"));
4477 	profileMenu->SetLabel(ID_PROFILE_S2L,_T("No Card"));
4478   }
4479 
4480 
4481   if (my_lisaconfig->slot3.IsSameAs(_T("dualparallel"),false))
4482   {
4483     if (my_lisaconfig->s3h.IsSameAs(_T("PROFILE"), false)) profileMenu->SetLabel(ID_PROFILE_S3U,wxT("Power ProFile on Slot 3 Upper Port"));
4484     if (my_lisaconfig->s3l.IsSameAs(_T("PROFILE"), false)) profileMenu->SetLabel(ID_PROFILE_S3L,wxT("Power ProFile on Slot 3 Lower Port"));
4485 
4486     if (my_lisaconfig->s3h.IsSameAs(_T("ADMP"), false)) profileMenu->SetLabel(ID_PROFILE_S3U,wxT("Power ADMP on Slot 3 Upper Port"));
4487     if (my_lisaconfig->s3l.IsSameAs(_T("ADMP"), false)) profileMenu->SetLabel(ID_PROFILE_S3L,wxT("Power ADMP on Slot 3 Lower Port"));
4488 
4489     if (my_lisaconfig->s3h.IsSameAs(_T("NOTHING"), false)) profileMenu->SetLabel(ID_PROFILE_S3U,wxT("Nothing on Slot 3 Upper Port"));
4490     if (my_lisaconfig->s3l.IsSameAs(_T("NOTHING"), false)) profileMenu->SetLabel(ID_PROFILE_S3L,wxT("Nothing on Slot 3 Lower Port"));
4491 
4492 	profileMenu->Enable(ID_PROFILE_S3U,( !my_lisaconfig->s3h.IsSameAs(_T("NOTHING"), false)) );
4493 	profileMenu->Enable(ID_PROFILE_S3L,( !my_lisaconfig->s3l.IsSameAs(_T("NOTHING"), false)) );
4494   }
4495   else
4496   {
4497 	profileMenu->Enable(ID_PROFILE_S3U,false );
4498 	profileMenu->Enable(ID_PROFILE_S3L,false );
4499 	profileMenu->SetLabel(ID_PROFILE_S3U,_T("No Card"));
4500 	profileMenu->SetLabel(ID_PROFILE_S3L,_T("No Card"));
4501   }
4502 
4503 }
4504 
4505 
OnProFilePowerX(int bit)4506 void LisaEmFrame::OnProFilePowerX(int bit)
4507 {
4508 
4509   int devtype=0;
4510 
4511   if (running)
4512    if (check_running_lisa_os()!=LISA_ROM_RUNNING)
4513    {
4514    switch(bit)
4515    {
4516  	case 2: if (my_lisaconfig->parallel.IsSameAs(_T("PROFILE"), false)) devtype=1; break;
4517 
4518     case 3: if (my_lisaconfig->s1h.IsSameAs(_T("PROFILE"), false)) devtype=1; break;
4519     case 4: if (my_lisaconfig->s1l.IsSameAs(_T("PROFILE"), false)) devtype=1; break;
4520 
4521     case 5: if (my_lisaconfig->s2h.IsSameAs(_T("PROFILE"), false)) devtype=1; break;
4522     case 6: if (my_lisaconfig->s2l.IsSameAs(_T("PROFILE"), false)) devtype=1; break;
4523 
4524     case 7: if (my_lisaconfig->s3h.IsSameAs(_T("PROFILE"), false)) devtype=1; break;
4525     case 8: if (my_lisaconfig->s3l.IsSameAs(_T("PROFILE"), false)) devtype=1; break;
4526     }
4527    }
4528 
4529   if (running && (IS_PARALLEL_PORT_ENABLED(bit)) && devtype)
4530   {
4531     if (yesnomessagebox("The Lisa may be using this Profile hard drive.  Powering it off may cause file system damage.  Are you sure  you wish to power it off?",
4532                         "DANGER!")==0) return;
4533   }
4534 
4535   profile_power^=(1<<(bit-2));
4536 
4537   UpdateProfileMenu();
4538 }
4539 
4540 
OnProFilePower(wxCommandEvent & WXUNUSED (event))4541 void LisaEmFrame::OnProFilePower( wxCommandEvent& WXUNUSED(event))  {OnProFilePowerX(2);}
OnProFileS1UPwr(wxCommandEvent & WXUNUSED (event))4542 void LisaEmFrame::OnProFileS1UPwr(wxCommandEvent& WXUNUSED(event))  {OnProFilePowerX(3);}
OnProFileS1LPwr(wxCommandEvent & WXUNUSED (event))4543 void LisaEmFrame::OnProFileS1LPwr(wxCommandEvent& WXUNUSED(event))  {OnProFilePowerX(4);}
OnProFileS2UPwr(wxCommandEvent & WXUNUSED (event))4544 void LisaEmFrame::OnProFileS2UPwr(wxCommandEvent& WXUNUSED(event))  {OnProFilePowerX(5);}
OnProFileS2LPwr(wxCommandEvent & WXUNUSED (event))4545 void LisaEmFrame::OnProFileS2LPwr(wxCommandEvent& WXUNUSED(event))  {OnProFilePowerX(6);}
OnProFileS3UPwr(wxCommandEvent & WXUNUSED (event))4546 void LisaEmFrame::OnProFileS3UPwr(wxCommandEvent& WXUNUSED(event))  {OnProFilePowerX(7);}
OnProFileS3LPwr(wxCommandEvent & WXUNUSED (event))4547 void LisaEmFrame::OnProFileS3LPwr(wxCommandEvent& WXUNUSED(event))  {OnProFilePowerX(8);}
4548 
OnProFilePwrOnAll(wxCommandEvent & WXUNUSED (event))4549 void LisaEmFrame::OnProFilePwrOnAll(wxCommandEvent& WXUNUSED(event))
4550 {  profile_power=127; UpdateProfileMenu();}
4551 
OnProFilePwrOffAll(wxCommandEvent & WXUNUSED (event))4552 void LisaEmFrame::OnProFilePwrOffAll(wxCommandEvent& WXUNUSED(event))
4553 {
4554   if (running && profile_power)
4555   {
4556     if (yesnomessagebox("Lisa is using the profile drives. Are you sure you wish to remove power to all Profile drives?",
4557                         "DANGER!")==0) return;
4558   }
4559   profile_power=0; UpdateProfileMenu();
4560 }
4561 
4562 
OnNewProFile(wxCommandEvent & WXUNUSED (event))4563 void LisaEmFrame::OnNewProFile(wxCommandEvent& WXUNUSED(event))
4564 {      int sz;
4565        int blocks[]={9728,19456,32768,40960,65536,81920,131072};
4566        //               0     1     2     3     4     5     6
4567        //              5M   10M   16M   20M   32M   40M    64M
4568 
4569 	 char cfilename[MAXPATHLEN];
4570 	 wxFileDialog open(this,                        wxT("Create blank ProFile drive as:"),
4571 	                                                wxEmptyString,
4572 	                                                wxT("lisaem-profile.dc42"),
4573 	                                                wxT("Disk Copy (*.dc42)|*.dc42|All (*.*)|*.*"),
4574 	                                                (long int)wxFD_SAVE,wxDefaultPosition);
4575 
4576 	 if (open.ShowModal()==wxID_OK)
4577 	 {
4578 	 wxString filename=open.GetPath();
4579 	 strncpy(cfilename,filename.fn_str(),MAXPATHLEN);
4580      sz=pickprofilesize(cfilename);  if (sz<0 || sz>6) return;
4581      int i=dc42_create(cfilename,"-lisaem.sunder.net hd-",blocks[sz]*512,blocks[sz]*20);
4582      if (i)
4583         wxMessageBox(wxT("Could not create the file to store the Profile.\n\nDo you have permission to write to this folder?\nIs there enough free disk space?"),
4584         wxT("Failed to create drive!"));
4585      }
4586 }
4587 
4588 
4589 
4590 
4591 
4592 
4593 
eject_floppy_animation(void)4594 extern "C" void eject_floppy_animation(void)
4595 {
4596  if ((my_lisawin->floppystate & FLOPPY_ANIM_MASK)==FLOPPY_PRESENT)          // initiate eject animation sequence
4597      {my_lisawin->floppystate=FLOPPY_NEEDS_REDRAW|FLOPPY_INSERT_2; return;}
4598 
4599    return;
4600 }
4601 
4602 
floppy_motor_sounds(int track)4603 extern "C" void floppy_motor_sounds(int track)
4604 {
4605 // there really are 3-4 speeds, however, my admittedly Bolt Thrower damaged ears can only distinguish two  :)
4606 // close enough for government work, I guess.
4607 
4608 #ifndef __WXMSW__
4609  if (wxSound::IsPlaying()) return;       // doesn't work on windows
4610 #else
4611  if (my_lisaframe->soundplaying)
4612     if (my_lisaframe->soundsw.Time()<200) return;
4613 my_lisaframe->soundplaying=1;
4614 my_lisaframe->soundsw.Start(0);
4615 #endif
4616  wxSound::Stop();
4617 
4618  if (sound_effects_on)
4619  {
4620    if (track>35)  {if (my_floppy_motor1->IsOk()) my_floppy_motor1->Play(wxSOUND_ASYNC);}
4621    else           {if (my_floppy_motor2->IsOk()) my_floppy_motor2->Play(wxSOUND_ASYNC);}
4622  }
4623 
4624 }
4625 
4626 
4627 
4628 
OnFLOPPY(wxCommandEvent & WXUNUSED (event))4629 void LisaEmFrame::OnFLOPPY(wxCommandEvent& WXUNUSED(event)) {OnxFLOPPY();}
4630 
OnxFLOPPY(void)4631 void LisaEmFrame::OnxFLOPPY(void)
4632 {
4633     if ((my_lisawin->floppystate & FLOPPY_ANIM_MASK)!=FLOPPY_EMPTY) {
4634         wxMessageBox(_T("A previously inserted diskette is still in the drive. "
4635             "Please eject the diskette before inserting another."),
4636             _T("Diskette is already inserted!"), wxICON_INFORMATION | wxOK);
4637         return;
4638     }
4639 
4640     pause_run();
4641 
4642     wxString openfile;
4643     wxFileDialog open(this,                     wxT("Insert a Lisa diskette"),
4644                                                 wxEmptyString,
4645                                                 wxEmptyString,
4646                                                 wxT("Disk Copy (*.dc42)|*.dc42|DART (*.dart)|*.dart|All (*.*)|*.*"),
4647                                                 (long int)wxFD_OPEN,wxDefaultPosition);
4648     if (open.ShowModal()==wxID_OK)              openfile=open.GetPath();
4649 
4650     resume_run();
4651 
4652 
4653     if (!openfile.Len()) return;
4654     const char *s = openfile.fn_str();
4655 
4656     if (my_lisaframe->running) {
4657         if (floppy_insert((char *)s)) return;
4658     } else {
4659         floppy_to_insert = openfile;
4660     }
4661 
4662     if ((my_lisawin->floppystate & FLOPPY_ANIM_MASK)==FLOPPY_EMPTY) {
4663         // initiate insert animation sequence
4664         my_lisawin->floppystate=FLOPPY_NEEDS_REDRAW|FLOPPY_ANIMATING|FLOPPY_INSERT_0;
4665      }
4666 }
4667 
4668 
OnNewFLOPPY(wxCommandEvent & WXUNUSED (event))4669 void LisaEmFrame::OnNewFLOPPY(wxCommandEvent& WXUNUSED(event)) {OnxNewFLOPPY();}
4670 
OnxNewFLOPPY(void)4671 void LisaEmFrame::OnxNewFLOPPY(void)
4672 {
4673     if (!my_lisaframe->running) {
4674         wxMessageBox(_T("Please turn the Lisa on before inserting a diskette."),
4675             _T("The Lisa is Off"), wxICON_INFORMATION | wxOK);
4676         return;
4677     }
4678 
4679     if ((my_lisawin->floppystate & FLOPPY_ANIM_MASK)!=FLOPPY_EMPTY) {
4680         wxMessageBox(_T("A previously inserted diskette is still in the drive. "
4681             "Please eject the diskette before inserting another."),
4682             _T("Diskette is already inserted!"), wxICON_INFORMATION | wxOK);
4683         return;
4684     }
4685 
4686     pause_run();
4687 
4688     wxString openfile;
4689     wxFileDialog open(this,                     wxT("Create and insert a blank microdiskette image"),
4690                                                 wxEmptyString,
4691                                                 wxT("blank.dc42"),
4692                                                 wxT("Disk Copy (*.dc42)|*.dc42|All (*.*)|*.*"),
4693                                                 (long int)wxFD_SAVE,wxDefaultPosition);
4694     if (open.ShowModal()==wxID_OK)              openfile=open.GetPath();
4695 
4696     resume_run();
4697     if (!openfile.Len()) return;
4698 
4699 
4700 
4701     const char *s = openfile.fn_str();
4702     int i = dc42_create((char *)s,"-not a Macintosh disk-", 400*512*2,400*2*12);
4703     if (i)  {
4704         wxMessageBox(_T("Could not create the diskette"),
4705             _T("Sorry"), wxICON_INFORMATION | wxOK);
4706         return;
4707     } else {
4708         floppy_insert((char *)s);
4709     }
4710 
4711 
4712  if ((my_lisawin->floppystate & FLOPPY_ANIM_MASK)==FLOPPY_EMPTY) {
4713      // initiate insert animation sequence
4714      my_lisawin->floppystate=FLOPPY_NEEDS_REDRAW|FLOPPY_ANIMATING|FLOPPY_INSERT_0;
4715  }
4716 }
4717 
4718 //  for future use - for when we figure out the right way to turn of skins on the fly
4719 //  - the real issue is the window size mechanism doesn't work properly.  won't prevent the user
4720 //  from stretching the window, or making it too small.  also in win32/linux with skins off
4721 //  the window is too small - shows scrollbars, but it allows stretching past the lisa screen bitmap
4722 //  which causes garbage in the non-refreshed space.
UnloadImages(void)4723 void LisaEmFrame::UnloadImages(void)
4724 {
4725    if (display_image)   {   delete display_image; display_image  = NULL;}
4726 
4727    if ( my_skinDC     )  {  delete my_skinDC;     my_skinDC      = NULL;}
4728    if ( my_skin0DC    )  {  delete my_skin0DC;    my_skin0DC     = NULL;}
4729    if ( my_skin1DC    )  {  delete my_skin1DC;    my_skin1DC     = NULL;}
4730    if ( my_skin2DC    )  {  delete my_skin2DC;    my_skin2DC     = NULL;}
4731    if ( my_skin3DC    )  {  delete my_skin3DC;    my_skin3DC     = NULL;}
4732    if ( my_floppy0DC  )  {  delete my_floppy0DC;  my_floppy0DC   = NULL;}
4733    if ( my_floppy1DC  )  {  delete my_floppy1DC;  my_floppy1DC   = NULL;}
4734    if ( my_floppy2DC  )  {  delete my_floppy2DC;  my_floppy2DC   = NULL;}
4735    if ( my_floppy3DC  )  {  delete my_floppy3DC;  my_floppy3DC   = NULL;}
4736    if ( my_floppy4DC  )  {  delete my_floppy4DC;  my_floppy4DC   = NULL;}
4737    if ( my_poweronDC  )  {  delete my_poweronDC;  my_poweronDC   = NULL;}
4738    if ( my_poweroffDC )  {  delete my_poweroffDC; my_poweroffDC  = NULL;}
4739 
4740    if ( my_skin       )  {  delete my_skin;       my_skin        = NULL;}
4741    if ( my_skin0      )  {  delete my_skin0;      my_skin0       = NULL;}
4742    if ( my_skin1      )  {  delete my_skin1;      my_skin1       = NULL;}
4743    if ( my_skin2      )  {  delete my_skin2;      my_skin2       = NULL;}
4744    if ( my_skin3      )  {  delete my_skin3;      my_skin3       = NULL;}
4745    if ( my_floppy0    )  {  delete my_floppy0;    my_floppy0     = NULL;}
4746    if ( my_floppy1    )  {  delete my_floppy1;    my_floppy1     = NULL;}
4747    if ( my_floppy2    )  {  delete my_floppy2;    my_floppy2     = NULL;}
4748    if ( my_floppy3    )  {  delete my_floppy3;    my_floppy3     = NULL;}
4749    if ( my_floppy4    )  {  delete my_floppy4;    my_floppy4     = NULL;}
4750    if ( my_poweron    )  {  delete my_poweron;    my_poweron     = NULL;}
4751    if ( my_poweroff   )  {  delete my_poweroff;   my_poweroff    = NULL;}
4752 
4753    skins_on=0;
4754 
4755    int x,y;
4756    my_lisawin->SetClientSize(wxSize(effective_lisa_vid_size_x,effective_lisa_vid_size_y));     // LisaWin //
4757    my_lisawin->GetClientSize(&x,&y);                                                           // LisaWin //
4758    my_lisawin->GetSize(&x,&y);                                                                 // LisaWin //
4759 
4760    screen_origin_x=(x  - effective_lisa_vid_size_x)>>1;                                        // center display
4761    screen_origin_y=(y  - effective_lisa_vid_size_y)>>1;                                        // on skinless
4762    screen_origin_x= (screen_origin_x<0 ? 0:screen_origin_x);
4763    screen_origin_y= (screen_origin_y<0 ? 0:screen_origin_y);
4764 
4765 
4766 // X11, Windows return too small a value for getsize
4767    x+=WINXDIFF; y+=WINYDIFF;
4768    SetMaxSize(wxSize(ISKINSIZE));                                                              // Frame   //
4769    SetMinSize(wxSize(720,384));                                                                // Frame   //
4770 
4771    SendSizeEvent();
4772 }
4773 
LoadImages(void)4774 void LisaEmFrame::LoadImages(void)
4775 {
4776 
4777 /*
4778  * On MacOS X, load the images from the Resources/ dir inside the app bundle.
4779  * Much faster than WX's breathtakingly slow parsing of XPMs, and much
4780  * smaller too since we can use PNGs.
4781  * On Linux/Win32 use embedded XPM strings/BMP resources.
4782  */
4783 
4784 if (skins_on)
4785 {
4786    if (!my_skin) my_skin     = new wxBitmap(ISKINSIZEX,ISKINSIZEY,DEPTH);//, -1);  //20061228//
4787    if (display_image)   {   delete display_image; display_image  = NULL;}
4788 
4789    wxString pngfile;
4790    wxStandardPathsBase& stdp = wxStandardPaths::Get();
4791    wxString rscDir = stdp.GetResourcesDir() + wxFileName::GetPathSeparator(wxPATH_NATIVE);
4792 
4793     // stare not upon the insanity that predated this code, for it was written by drunkards! (*Burp*)
4794 
4795 // OS X, and Unixen will use resource dirs to load png files
4796 #ifndef __WXMSW__
4797 
4798    pngfile=rscDir + _T("lisaface0.png");  if (!my_skin0)    my_skin0    = new wxBitmap(pngfile, wxBITMAP_TYPE_PNG);
4799    pngfile=rscDir + _T("lisaface1.png");  if (!my_skin1)    my_skin1    = new wxBitmap(pngfile, wxBITMAP_TYPE_PNG);
4800    pngfile=rscDir + _T("lisaface2.png");  if (!my_skin2)    my_skin2    = new wxBitmap(pngfile, wxBITMAP_TYPE_PNG);
4801    pngfile=rscDir + _T("lisaface3.png");  if (!my_skin3)    my_skin3    = new wxBitmap(pngfile, wxBITMAP_TYPE_PNG);
4802 
4803    pngfile=rscDir + _T("floppy0.png");    if (!my_floppy0)  my_floppy0  = new wxBitmap(pngfile, wxBITMAP_TYPE_PNG);
4804    pngfile=rscDir + _T("floppy1.png");    if (!my_floppy1)  my_floppy1  = new wxBitmap(pngfile, wxBITMAP_TYPE_PNG);
4805    pngfile=rscDir + _T("floppy2.png");    if (!my_floppy2)  my_floppy2  = new wxBitmap(pngfile, wxBITMAP_TYPE_PNG);
4806    pngfile=rscDir + _T("floppy3.png");    if (!my_floppy3)  my_floppy3  = new wxBitmap(pngfile, wxBITMAP_TYPE_PNG);
4807    pngfile=rscDir + _T("floppyN.png");    if (!my_floppy4)  my_floppy4  = new wxBitmap(pngfile, wxBITMAP_TYPE_PNG);
4808 
4809    pngfile=rscDir + _T("power_on.png");   if (!my_poweron ) my_poweron  = new wxBitmap(pngfile, wxBITMAP_TYPE_PNG);
4810    pngfile=rscDir + _T("power_off.png");  if (!my_poweroff) my_poweroff = new wxBitmap(pngfile, wxBITMAP_TYPE_PNG);
4811 
4812 // windoze will load BMP resources from the .EXE file
4813 #else
4814    if (!my_skin0)     my_skin0     = new wxBITMAP( lisaface0 );
4815    if (!my_skin1)     my_skin1     = new wxBITMAP( lisaface1 );
4816    if (!my_skin2)     my_skin2     = new wxBITMAP( lisaface2 );
4817    if (!my_skin3)     my_skin3     = new wxBITMAP( lisaface3 );
4818 
4819    if (!my_floppy0)   my_floppy0   = new wxBITMAP( floppy0   );
4820    if (!my_floppy1)   my_floppy1   = new wxBITMAP( floppy1   );
4821    if (!my_floppy2)   my_floppy2   = new wxBITMAP( floppy2   );
4822    if (!my_floppy3)   my_floppy3   = new wxBITMAP( floppy3   );
4823    if (!my_floppy4)   my_floppy4   = new wxBITMAP( floppyN   );
4824 
4825    if (!my_poweron )  my_poweron   = new wxBITMAP( power_on  );
4826    if (!my_poweroff)  my_poweroff  = new wxBITMAP( power_off );
4827 
4828 #endif
4829 
4830    if (!my_skinDC)     my_skinDC    = new wxMemoryDC;
4831    if (!my_skin0DC)    my_skin0DC   = new wxMemoryDC;
4832    if (!my_skin1DC)    my_skin1DC   = new wxMemoryDC;
4833    if (!my_skin2DC)    my_skin2DC   = new wxMemoryDC;
4834    if (!my_skin3DC)    my_skin3DC   = new wxMemoryDC;
4835 
4836    if (!my_floppy0DC)  my_floppy0DC = new wxMemoryDC;
4837    if (!my_floppy1DC)  my_floppy1DC = new wxMemoryDC;
4838    if (!my_floppy2DC)  my_floppy2DC = new wxMemoryDC;
4839    if (!my_floppy3DC)  my_floppy3DC = new wxMemoryDC;
4840    if (!my_floppy4DC)  my_floppy4DC = new wxMemoryDC;
4841 
4842    if (!my_poweronDC)  my_poweronDC = new wxMemoryDC;
4843    if (!my_poweroffDC) my_poweroffDC= new wxMemoryDC;
4844 
4845    my_skinDC->SelectObject(*my_skin);
4846 
4847    my_skin0DC->SelectObject(*my_skin0);
4848    my_skin1DC->SelectObject(*my_skin1);
4849    my_skin2DC->SelectObject(*my_skin2);
4850    my_skin3DC->SelectObject(*my_skin3);
4851 
4852    int y=0;
4853    my_skinDC->Blit(0,y, my_skin0->GetWidth(),my_skin0->GetHeight(),my_skin0DC, 0,0 ,wxCOPY, false);   y+=my_skin0->GetHeight();
4854    my_skinDC->Blit(0,y, my_skin1->GetWidth(),my_skin1->GetHeight(),my_skin1DC, 0,0 ,wxCOPY, false);   y+=my_skin1->GetHeight();
4855    my_skinDC->Blit(0,y, my_skin2->GetWidth(),my_skin2->GetHeight(),my_skin2DC, 0,0 ,wxCOPY, false);   y+=my_skin2->GetHeight();
4856    my_skinDC->Blit(0,y, my_skin3->GetWidth(),my_skin3->GetHeight(),my_skin3DC, 0,0 ,wxCOPY, false); //y+=my_skin3->GetHeight();
4857 
4858    my_floppy0DC->SelectObject(*my_floppy0);
4859    my_floppy1DC->SelectObject(*my_floppy1);
4860    my_floppy2DC->SelectObject(*my_floppy2);
4861    my_floppy3DC->SelectObject(*my_floppy3);
4862    my_floppy4DC->SelectObject(*my_floppy4);
4863    my_poweronDC->SelectObject(*my_poweron);
4864    my_poweroffDC->SelectObject(*my_poweroff);
4865 
4866    my_lisawin->SetMinSize(wxSize(IWINSIZE));
4867    my_lisawin->SetClientSize(wxSize(IWINSIZE));                                                     // Lisawin   //
4868    my_lisawin->SetMaxSize(wxSize(ISKINSIZE));                                                       // Lisawin   //
4869    my_lisawin->SetScrollbars(ISKINSIZEX/100, ISKINSIZEY/100,  100,100,  0,0,  true);                // Lisawin   //
4870    my_lisawin->EnableScrolling(true,true);                                                          // Lisawin   //
4871 
4872    SendSizeEvent();
4873 
4874    screen_origin_x=140;
4875    screen_origin_y=130;
4876   }
4877 
4878 }
4879 
4880 
4881 
LisaEmFrame(const wxString & title)4882 LisaEmFrame::LisaEmFrame(const wxString& title)
4883        : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE)
4884 {
4885    effective_lisa_vid_size_y=500;
4886    wxInitAllImageHandlers();
4887 
4888    barrier=0;
4889    clx=0;
4890    lastt2 = 0;
4891    lastclk = 0;
4892    lastcrtrefresh=0;
4893    hostrefresh=1000/ 8;
4894 
4895    int x,y;
4896    y=myConfig->Read(_T("/lisaframe/sizey"),(long)0);
4897    x=myConfig->Read(_T("/lisaframe/sizex"),(long)0);
4898 
4899    if (x<=0 || x>4096 || y<=0 || y>2048) {x=IWINSIZEX;y=IWINSIZEY;}
4900    //wxScreenDC theScreen;
4901    //theScreen.GetSize(&screensizex,&screensizey);
4902 
4903    wxDisplaySize(&screensizex,&screensizey);
4904    // Grrr! OS X sometimes returns garbage here
4905    if (screensizex< 0 || screensizex>8192 || screensizey<0 || screensizey>8192)
4906       {ALERT_LOG(0,"Got Garbage screen size: %d,%d",screensizex,screensizey);
4907 	   screensizex=1024; screensizey=768;}
4908 
4909    if (x>screensizex || y>screensizey)  // make sure we don't get too big
4910       {
4911         x=MIN(screensizex-100,IWINSIZEX);
4912         y=MIN(screensizey-150,IWINSIZEY);
4913       }
4914 
4915 #ifndef __WXOSX__
4916     SetIcon( wxICON( lisa2icon ));
4917 #endif
4918 
4919     if (skins_on)
4920     {
4921        SetMinSize(wxSize(IWINSIZE));                                                                // Frame    //
4922        if (x<IWINSIZEX || y<IWINSIZEY) {x=IWINSIZEX; y=IWINSIZEY;}
4923        SetMinSize(wxSize(720,384));
4924        SetClientSize(wxSize(x,y));                                                                  // Frame    //
4925        GetClientSize(&dwx,&dwy);
4926        dwx-=x; dwy-=y;
4927        SetClientSize(wxSize(x-dwx,y-dwy));
4928        SetMaxSize(wxSize(ISKINSIZE));                                                               // Frame    //
4929     }                                                                                               // Frame    //
4930     else
4931     {
4932        // try to fit the Lisa's display on the screen at least.
4933        if (x<effective_lisa_vid_size_x || y<effective_lisa_vid_size_y)
4934 	      {x=effective_lisa_vid_size_x;   y=effective_lisa_vid_size_y;}
4935 
4936        // but if it's too big, ensure we don't go over the display'size.
4937        x=MIN(screensizex-100,x); y=MIN(screensizey-150,x);
4938 
4939        SetMinSize(wxSize(720,384));
4940 	   SetClientSize(wxSize(x,y));                                                                  // Frame    //
4941        GetClientSize(&dwx,&dwy);
4942        dwx-=x; dwy-=y;
4943 
4944        SetMaxSize(wxSize(ISKINSIZE));                                                               // Frame    //
4945  	}
4946 
4947 
4948     buildscreenymap();
4949 
4950     // Create a menu bar
4951     fileMenu     = new wxMenu;
4952     editMenu     = new wxMenu;
4953     keyMenu      = new wxMenu;
4954     DisplayMenu  = new wxMenu;
4955     throttleMenu = new wxMenu;
4956 	profileMenu  = new wxMenu;
4957     helpMenu     = new wxMenu;
4958 
4959 
4960 
4961 
4962 	profileMenu->Append(ID_PROFILE_ALL_ON,   wxT("Power On all Parallel Devices"), wxT("Powers on all parallel port attached devices.")  );
4963     profileMenu->Append(ID_PROFILE_ALL_OFF,  wxT("Power off all Parallel Devices"), wxT("Shuts off all parallel port attached devices.")  );
4964 
4965     profileMenu->AppendSeparator();
4966 
4967 	profileMenu->AppendCheckItem(ID_PROFILEPWR,       wxT("Power ProFile on Parallel Port"), wxT("Toggles power to the Profile drive on the parallel port") );
4968 
4969 	profileMenu->AppendSeparator();
4970 
4971     profileMenu->AppendCheckItem(ID_PROFILE_S1U,      wxT("Power ProFile on Slot 1 Upper Port"),wxT("Toggle power to the device") );
4972 	profileMenu->AppendCheckItem(ID_PROFILE_S1L,      wxT("Power ProFile on Slot 1 Lower Port"),wxT("Toggle power to the device") );
4973 	profileMenu->AppendSeparator();
4974 
4975     profileMenu->AppendCheckItem(ID_PROFILE_S2U,      wxT("Power ProFile on Slot 2 Upper Port"),wxT("Toggle power to the device") );
4976     profileMenu->AppendCheckItem(ID_PROFILE_S2L,      wxT("Power ProFile on Slot 2 Lower Port"),wxT("Toggle power to the device") );
4977 	profileMenu->AppendSeparator();
4978 
4979     profileMenu->AppendCheckItem(ID_PROFILE_S3U,      wxT("Power ProFile on Slot 3 Upper Port"),wxT("Toggle power to the device") );
4980     profileMenu->AppendCheckItem(ID_PROFILE_S3L,      wxT("Power ProFile on Slot 3 Lower Port"),wxT("Toggle power to the device") );
4981 
4982     editMenu->Append(wxID_PASTE, wxT("Paste") ,       wxT("Paste clipboard text to keyboard.") );
4983 
4984     DisplayMenu->AppendCheckItem(ID_VID_AA  ,         wxT("AntiAliased")           ,  wxT("Aspect Corrected with Anti Aliasing") );
4985     DisplayMenu->AppendCheckItem(ID_VID_AAG ,         wxT("AntiAliased with Gray Replacement"),  wxT("Aspect Corrected with Anti Aliasing and Gray Replacing") );
4986     //DisplayMenu->AppendCheckItem(ID_VID_SCALED,  wxT("Scaled")                ,  wxT("Scaled by wxWidgets") );
4987 
4988     DisplayMenu->AppendSeparator();
4989     DisplayMenu->AppendCheckItem(ID_VID_SY  ,         wxT("Raw")                   ,  wxT("Uncorrected Aspect Ratio") );
4990     DisplayMenu->AppendSeparator();
4991 
4992     DisplayMenu->AppendCheckItem(ID_VID_DY  ,         wxT("Double Y")              ,  wxT("Double Vertical Size") );
4993     DisplayMenu->AppendCheckItem(ID_VID_2X3Y,         wxT("Double X, Triple Y")    ,  wxT("Corrected Aspect Ratio, Large Display") );
4994 
4995     DisplayMenu->AppendSeparator();
4996 
4997     DisplayMenu->AppendCheckItem(ID_VID_SKINS_ON,     wxT("Turn Skins On"),         wxT("Turn on skins") );
4998     DisplayMenu->AppendCheckItem(ID_VID_SKINS_OFF,    wxT("Turn Skins Off"),        wxT("Turn off skins") );
4999 
5000     DisplayMenu->AppendSeparator();
5001 
5002   // reinstated as per request by Kallikak
5003     DisplayMenu->AppendCheckItem(ID_REFRESH_60Hz,wxT("60Hz Refresh"),wxT("60Hz Display Refresh - skip no frames - for fast machines"));
5004     DisplayMenu->AppendCheckItem(ID_REFRESH_20Hz,wxT("20Hz Refresh"),wxT("20Hz Display Refresh - display every 2nd frame"));
5005     DisplayMenu->AppendCheckItem(ID_REFRESH_12Hz,wxT("12Hz Refresh"),wxT("12Hz Display Refresh - display every 5th frame - for slow machines"));
5006     DisplayMenu->AppendCheckItem(ID_REFRESH_8Hz,wxT( " 8Hz Refresh"),wxT("8Hz Display Refresh - display every 7th frame - for slow machines"));
5007     DisplayMenu->AppendCheckItem(ID_REFRESH_4Hz,wxT( " 4Hz Refresh"),wxT("4Hz Display Refresh - display every 9th frame - for super slow machines"));
5008 
5009     DisplayMenu->AppendSeparator();
5010 
5011     DisplayMenu->AppendCheckItem(ID_HIDE_HOST_MOUSE,wxT("Hide Host Mouse Pointer"),wxT("Hides the host mouse pointer - may cause lag"));
5012 
5013 
5014     throttleMenu->AppendCheckItem(ID_THROTTLE5,       wxT("5 MHz")                  , wxT("5 MHz - Stock Lisa Speed, recommended.") );
5015     throttleMenu->AppendCheckItem(ID_THROTTLE8,       wxT("8 MHz")                  , wxT("8 MHz - Original Macintosh 128 Speed") );
5016     throttleMenu->AppendCheckItem(ID_THROTTLE10,      wxT("10 MHz")                 , wxT("10Mhz"));
5017     throttleMenu->AppendCheckItem(ID_THROTTLE12,      wxT("12 MHz")                 , wxT("12Mhz"));
5018     throttleMenu->AppendCheckItem(ID_THROTTLE16,      wxT("16 MHz")                 , wxT("16Mhz"));
5019     throttleMenu->AppendCheckItem(ID_THROTTLE32,      wxT("32 MHz")                 , wxT("32Mhz - For modern machines") );
5020 
5021     throttleMenu->AppendSeparator();
5022 
5023 	throttleMenu->AppendCheckItem(ID_ET100_75,       wxT("Higher 68000 Performance"),     wxT("Normal 100/75ms duty timer - faster emulated CPU, less smooth animations"));
5024     throttleMenu->AppendCheckItem(ID_ET50_30,        wxT("Balanced 68000/Graphics"),      wxT("Medium  50/30ms duty timer - smoother animation, slower CPU"));
5025     throttleMenu->AppendCheckItem(ID_ET40_25,        wxT("Smoother Graphics"),            wxT("Small   40/25ms duty timer - even smoother animation, slower CPU"));
5026     throttleMenu->AppendCheckItem(ID_ET30_20,        wxT("Smoothest display, lowest 68000 Performance"),     wxT("Tiny    30/20ms duty timer - smoothest animation, slowest CPU"));
5027 
5028 
5029 //    throttleMenu->AppendCheckItem(ID_THROTTLEX,  wxT("Unthrottled")            , wxT("Dangerous to your machine!") );
5030 
5031 
5032     // The "About" item should be in the help menu
5033 
5034     //helpMenu->Append(wxID_ABOUT, wxT("&License"),                 wxT("License Information"));
5035     //helpMenu->AppendSeparator();
5036     //helpMenu->Append(wxID_ABOUT, wxT("Help \tF1"),                wxT("Emulator Manual"));
5037     //helpMenu->Append(wxID_ABOUT, wxT("Lisa Help"),                wxT("How to use Lisa software"));
5038     //helpMenu->AppendSeparator();
5039 
5040 	helpMenu->Append(wxID_ABOUT, wxT("&About LisaEm"),                   wxT("About the Lisa Emulator"));
5041 	#ifndef __WXOSX__
5042 	    helpMenu->AppendSeparator();
5043 	#endif
5044 
5045     helpMenu->Append(ID_LISAWEB, wxT("Lisa Emulator Webpage"),    wxT("http://lisaem.sunder.net"));
5046     helpMenu->Append(ID_LISAFAQ, wxT("Lisa FAQ webpage"),         wxT("http://lisafaq.sunder.net"));
5047 
5048 
5049     keyMenu->Append(ID_POWERKEY,         wxT("Power Button"),     wxT("Push the Power Button"));
5050     keyMenu->Append(ID_APPLEPOWERKEY,    wxT("Apple+Power Button"),wxT("Push Apple + the Power Button"));
5051     keyMenu->AppendSeparator();
5052 
5053     keyMenu->Append(ID_KEY_APL_DOT,      wxT("Apple ."),          wxT("Apple + ."));
5054 
5055     keyMenu->Append(ID_KEY_APL_S,        wxT("Apple S"),          wxT("Apple + S"));
5056     keyMenu->Append(ID_KEY_APL_ENTER,    wxT("Apple Enter"),      wxT("Apple + Enter"));
5057     keyMenu->Append(ID_KEY_APL_RENTER,   wxT("Apple Right Enter"),wxT("Apple + Numpad Enter"));
5058 
5059     keyMenu->Append(ID_KEY_APL_1,        wxT("Apple 1"),          wxT("Apple + 1"));
5060     keyMenu->Append(ID_KEY_APL_2,        wxT("Apple 2"),          wxT("Apple + 2"));
5061     keyMenu->Append(ID_KEY_APL_3,        wxT("Apple 3"),          wxT("Apple + 3"));
5062 
5063 
5064     keyMenu->Append(ID_KEY_OPT_0,        wxT("Option 0"),         wxT("Option 0"));
5065     keyMenu->Append(ID_KEY_OPT_4,        wxT("Option 4"),         wxT("Option 4"));
5066     keyMenu->Append(ID_KEY_OPT_7,        wxT("Option 7"),         wxT("Option 7"));
5067 
5068     keyMenu->AppendSeparator();
5069     keyMenu->Append(ID_KEY_NMI,          wxT("NMI Key"),          wxT("Send Non-Maskable Interrupt key - for LisaBug"));
5070 	keyMenu->Append(ID_KEY_RESET,        wxT("Reset Button"),     wxT("Reset the Lisa - use only if the running OS has crashed!"));
5071 
5072     keyMenu->AppendSeparator();
5073     keyMenu->AppendCheckItem(ID_ASCIIKB, wxT("ASCII Keyboard"),    wxT("Translate host keys into ASCII, then to Lisa keys (preferred)"));
5074     keyMenu->AppendCheckItem(ID_RAWKB,   wxT("Raw Keyboard"),      wxT("Map host keys to Lisa keys directly"));
5075     keyMenu->AppendCheckItem(ID_RAWKBBUF,wxT("Raw Buffered Keyboard"),wxT("Map host keys to Lisa keys directly, buffer to prevent repeats"));
5076     //not-yet-used//keyMenu->AppendSeparator();
5077     //not-yet-used//keyMenu->Append(ID_KEYBOARD,         wxT("Keyboard"),         wxT("Lisa Keyboard"));
5078 
5079     fileMenu->Append(wxID_OPEN,          wxT("Open Preferences"), wxT("Open a LisaEm Preferences file"));
5080     fileMenu->Append(wxID_SAVEAS,        wxT("Save Preferences As"), wxT("Save current LisaEm Preferences to a new file"));
5081     fileMenu->Append(wxID_PREFERENCES,   wxT("Preferences"),      wxT("Configure this Lisa"));
5082 
5083     fileMenu->AppendSeparator();
5084 
5085     fileMenu->AppendCheckItem(ID_RUN,    wxT("Run"), wxT("Run Emulation") );
5086     fileMenu->AppendCheckItem(ID_PAUSE,  wxT("Pause"), wxT("Pause Emulation") );
5087 
5088     fileMenu->AppendSeparator();
5089 
5090     fileMenu->Append(  ID_FLOPPY,        wxT("Insert diskette"),    wxT("Insert a disk image"));
5091     fileMenu->Append(ID_NewFLOPPY,       wxT("Insert blank diskette"),wxT("Create, and insert, a blank disk image"));
5092     fileMenu->AppendSeparator();
5093 	fileMenu->Append(ID_PROFILE_NEW,     wxT("Create new Profile image"), wxT("Creates a blank ProFile storage file")  );
5094     fileMenu->AppendSeparator();
5095 
5096     fileMenu->Append(ID_SCREENSHOT,      wxT("Screenshot"),       wxT("Save the current screen as an image"));
5097     fileMenu->Append(ID_SCREENSHOT2,     wxT("Full Screenshot"),  wxT("Save a screenshot along with the skin"));
5098     fileMenu->Append(ID_SCREENSHOT3,     wxT("Raw Screenshot"),   wxT("Save a raw screenshot"));
5099 
5100     fileMenu->AppendSeparator();
5101 
5102     fileMenu->Append(ID_FUSH_PRNT,       wxT("Flush Print Jobs"),   wxT("Force pending print jobs to print"));
5103 
5104     fileMenu->AppendSeparator();
5105 
5106 #ifndef __WXMSW__
5107 #ifdef TRACE
5108     fileMenu->AppendCheckItem(ID_DEBUG,  wxT("Trace Log"),     wxT("Trace Log On/Off"));
5109     fileMenu->AppendSeparator();
5110 #endif
5111 #endif
5112 
5113 
5114     fileMenu->Append(wxID_EXIT,          wxT("Exit"),             wxT("Quit the Emulator"));
5115 
5116     // Now append the freshly created menu to the menu bar...
5117 
5118     menuBar = new wxMenuBar();
5119 
5120     menuBar->Append(fileMenu, wxT("File"));
5121     menuBar->Append(editMenu, wxT("Edit"));
5122     menuBar->Append(keyMenu,  wxT("Key"));
5123     menuBar->Append(DisplayMenu, wxT("Display"));
5124     menuBar->Append(throttleMenu, wxT("Throttle"));
5125     menuBar->Append(profileMenu, wxT("Parallel Port"));
5126 
5127     menuBar->Append(helpMenu, wxT("&Help"));
5128 
5129 
5130     SetMenuBar(menuBar);
5131 	UpdateProfileMenu();
5132 
5133     CreateStatusBar(1);
5134 
5135     SetStatusText(wxT("Welcome to the Lisa Emulator Project!"));
5136     soundplaying=0;
5137 
5138     if (!my_lisawin) my_lisawin = new LisaWin(this);
5139 
5140     my_lisawin->doubley = 0;
5141     my_lisawin->dirtyscreen = 1;
5142     my_lisawin->brightness = 0;
5143     my_lisawin->refresh_bytemap = 1;
5144 
5145    if (skins_on)
5146       {
5147            int x,y;
5148            LoadImages();
5149 
5150            x=my_skin->GetWidth();
5151            y=my_skin->GetHeight();
5152 
5153            my_lisawin->SetMaxSize(wxSize(x,y));
5154            my_skinDC->SelectObject(*my_skin);
5155 
5156            my_lisawin->SetVirtualSize(x,y);
5157            my_lisawin->SetScrollbars(x/100, y/100,  100,100,  0,0,  true);
5158            my_lisawin->EnableScrolling(true,true);
5159       }
5160    else
5161       {
5162            int x,y;
5163            y=myConfig->Read(_T("/lisaframe/sizey"),(long)0);
5164            x=myConfig->Read(_T("/lisaframe/sizex"),(long)0);
5165            if (x<effective_lisa_vid_size_x || y<effective_lisa_vid_size_y )
5166               {x=effective_lisa_vid_size_x;   y=effective_lisa_vid_size_y;}
5167 //           ALERT_LOG(0,"Setting frame size to:%d,%d",x,y);
5168 
5169 	       SetClientSize(wxSize(x,y));															 // Frame    //
5170            GetClientSize(&x,&y);                                                                 // Frame    //
5171 		   SetMinSize(wxSize(720,384));
5172            x+=WINXDIFF; y+=WINYDIFF;                                                             // LisaWin  //
5173            my_lisawin->SetClientSize(wxSize(x,y));
5174            my_lisawin->GetSize(&x,&y);                                                           // LisaWin  //
5175            // X11, Windows return too small a value for getsize
5176            x+=WINXDIFF; y+=WINYDIFF;                                                             // LisaWin  //
5177 
5178            my_lisawin->SetMaxSize(wxSize(ISKINSIZE));                                            // LisaWin  //
5179            my_lisawin->SetMinSize(wxSize(720,384));                                              // LisaWin  //
5180            my_lisawin->EnableScrolling(false,false);                                             // LisaWin  //
5181       }
5182 
5183    SendSizeEvent();
5184    my_lisawin->Show(true);
5185    fileMenu->Check(ID_PAUSE,false);
5186    fileMenu->Check(ID_RUN,  false);
5187 
5188 
5189    m_emulation_timer = new wxTimer(this, ID_EMULATION_TIMER);
5190    m_emulation_timer->Start(emulation_tick, wxTIMER_CONTINUOUS);
5191 }
5192 
5193 
OnFlushPrint(wxCommandEvent & WXUNUSED (event))5194 void LisaEmFrame::OnFlushPrint(wxCommandEvent& WXUNUSED(event))  {iw_enddocuments();iw_enddocuments();}
5195 
5196 
5197 // copied/based on wxWidgets samples image.cpp (c) 1998-2005 Robert Roebling
OnScreenshot(wxCommandEvent & event)5198 void LisaEmFrame::OnScreenshot(wxCommandEvent& event)
5199 {
5200  wxImage* image=NULL;
5201 
5202     wxString description;
5203 
5204     pause_run();
5205 
5206     if ( event.GetId()==ID_SCREENSHOT3)
5207          {
5208 		   int updated=0;
5209 		   uint32 a3,xx;
5210 		   uint16 val;
5211 		   uint8  d;
5212 
5213 		   uint8 bright[8];
5214 
5215   		   bright[0]=240;
5216   		   bright[1]=240;
5217   		   bright[2]=240;
5218            bright[4]=bright[5]=bright[6]=bright[7]=0;
5219 
5220            description = _T("Save RAW Screenshot");
5221            image = new class wxImage(lisa_vid_size_x, lisa_vid_size_y, true);
5222 
5223 		   for ( int yi=0; yi < lisa_vid_size_y; yi++)
5224 			    {
5225 				   for ( int xi=0; xi < lisa_vid_size_x;)
5226 					{ SETRGB16_RAW_X(xi,yi,{image->SetRGB(xi,yi,d,d,d+EXTRABLUE);});   }
5227 			    }
5228          }
5229     else  if ( event.GetId()==ID_SCREENSHOT2 && skins_on)
5230          {
5231           description = _T("Save Screenshot with Skin");
5232           image = new class wxImage(my_skin->ConvertToImage());
5233          }
5234     else if ( event.GetId()==ID_SCREENSHOT ||( event.GetId()==ID_SCREENSHOT2 && !skins_on) )
5235          {
5236 
5237           if (!skins_on) image = new class wxImage(my_lisabitmap->ConvertToImage());
5238           else {
5239   			    wxBitmap   *bitmap=NULL;
5240                 wxMemoryDC *dc=NULL;
5241 				dc=new class wxMemoryDC;
5242 
5243 			    bitmap=new class wxBitmap(effective_lisa_vid_size_x, effective_lisa_vid_size_y,DEPTH);
5244 		        dc->SelectObject(*bitmap);
5245 
5246  		        dc->Blit(0,0, effective_lisa_vid_size_x, effective_lisa_vid_size_y,
5247 	                      (skins_on ? my_skinDC:my_memDC),
5248 	                      screen_origin_x,screen_origin_y, wxCOPY, false);
5249 				DEBUG_LOG(0,"converting to image");
5250 
5251                 image = new class wxImage(bitmap->ConvertToImage());
5252 				delete bitmap;
5253 				delete dc;
5254                }
5255           description = _T("Save Screenshot");
5256 
5257          }
5258     else
5259          {
5260           resume_run();
5261 		  return;
5262 		 }
5263 
5264 
5265 wxString filter;
5266 #ifdef wxUSE_LIBPNG
5267                                         filter+=_T("PNG files (*.png)|");
5268                                         //filter+=_T("PNG files (*.png)|*.png|");
5269 #endif
5270 #ifdef wxUSE_LIBJPEG
5271                                         filter+=_T("JPEG files (*.jpg)|");
5272 #endif
5273 #ifdef wxUSE_LIBTIFF
5274                                         filter+=_T("TIFF files (*.tif)|");
5275 #endif
5276 
5277 // is this enabled, now that Unisys had the evil patent expire?
5278 #ifdef wxUSE_LIBGIF
5279                                         filter+=_T("GIF files (*.gif)|");
5280 #endif
5281 
5282 #ifdef wxUSE_PCX
5283                                         filter+=_T("PCX files (*.pcx)|");
5284 #endif
5285                                         filter+=_T("BMP files (*.bmp)|");
5286 
5287     wxString savefilename = wxFileSelector(   description,
5288                                             wxEmptyString,
5289                                             wxEmptyString,
5290                                             wxEmptyString,
5291                                                 filter,
5292 //#ifdef wxFD_SAVE
5293                                             wxFD_SAVE);
5294 //#else
5295 //                                            wxSAVE);
5296 //#endif
5297 
5298 
5299     if ( savefilename.empty() )  {resume_run();  return; }
5300 
5301     wxString extension;
5302     wxFileName::SplitPath(savefilename, NULL, NULL, &extension);
5303 
5304     if ( extension == _T("bpp") )
5305     {
5306             image->SetOption(wxIMAGE_OPTION_BMP_FORMAT, wxBMP_1BPP_BW);
5307     }
5308     else if ( extension == _T("png") )
5309     {
5310 
5311        if ( event.GetId()==ID_SCREENSHOT2 && skins_on)
5312           {
5313             image->SetOption(wxIMAGE_OPTION_PNG_FORMAT, wxPNG_TYPE_COLOUR );
5314           }
5315        else
5316           {
5317             image->SetOption(wxIMAGE_OPTION_PNG_FORMAT, wxPNG_TYPE_GREY);
5318             image->SetOption(wxIMAGE_OPTION_PNG_BITDEPTH, 8);
5319           }
5320     }
5321 
5322    image->SaveFile(savefilename);
5323    resume_run();
5324 }
5325 
5326 /* Connects a Dual Parallel port card to the specified slot (numbered 0-2). */
connect_2x_parallel_to_slot(int slot)5327 void connect_2x_parallel_to_slot(int slot)
5328 {
5329 
5330 //	ALERT_LOG(0,"Connecting Dual Parallel card to slot %d",slot+1);
5331 
5332     int low, high, v;
5333     switch (slot)
5334     {
5335         case 0:
5336             get_exs0_pending_irq = get_exs0_pending_irq_2xpar;
5337             low = Ox0000_slot1; high = Ox2000_slot1; v = 3;       // vias 3,4
5338             break;
5339         case 1:
5340             get_exs1_pending_irq = get_exs1_pending_irq_2xpar;
5341             low = Ox4000_slot2; high = Ox6000_slot2; v = 5;       // vias 5,6
5342             break;
5343         case 2:
5344             get_exs2_pending_irq = get_exs2_pending_irq_2xpar;
5345             low = Ox8000_slot3; high = Oxa000_slot3; v = 7;       // vias 7,8
5346             break;
5347         default:
5348            //ALERT_LOG(0, "Unknown slot number %d, should be 0-2!", slot);
5349            return;
5350     }
5351 
5352     mem68k_memptr    [low] = lisa_mptr_2x_parallel_l;
5353     mem68k_fetch_byte[low] = lisa_rb_2x_parallel_l;
5354     mem68k_fetch_word[low] = lisa_rw_2x_parallel_l;
5355     mem68k_fetch_long[low] = lisa_rl_2x_parallel_l;
5356     mem68k_store_byte[low] = lisa_wb_2x_parallel_l;
5357     mem68k_store_word[low] = lisa_ww_2x_parallel_l;
5358     mem68k_store_long[low] = lisa_wl_2x_parallel_l;
5359 
5360     mem68k_memptr    [high] = lisa_mptr_2x_parallel_h;
5361     mem68k_fetch_byte[high] = lisa_rb_2x_parallel_h;
5362     mem68k_fetch_word[high] = lisa_rw_2x_parallel_h;
5363     mem68k_fetch_long[high] = lisa_rl_2x_parallel_h;
5364     mem68k_store_byte[high] = lisa_wb_2x_parallel_h;
5365     mem68k_store_word[high] = lisa_ww_2x_parallel_h;
5366     mem68k_store_long[high] = lisa_wl_2x_parallel_h;
5367 
5368     reset_via(v);
5369     reset_via(v+1);
5370     via[v].active = 1;
5371     via[v+1].active = 1;
5372 }
5373 
5374 /* Connects a printer/profile to the specified VIA */
connect_device_to_via(int v,wxString device,wxString * file)5375 void connect_device_to_via(int v, wxString device, wxString *file)
5376 {
5377 	char tmp[MAXPATHLEN];
5378 
5379 //    if (v==2) {ALERT_LOG(0,"Connecting %s filename:%s to VIA #%d (motherboard parallel port)",device.c_str(),file->c_str(), v );}
5380 // 	  else      {ALERT_LOG(0,"Connecting %s filename:%s to VIA #%d (slot #%d %s)",device.c_str(),file->c_str(), v,1+((v-2)/2), ((v&1) ? "upper":"lower") );}
5381 
5382     if (device.IsSameAs(_T("ADMP"), false))
5383     {
5384         via[v].ADMP = v;
5385         ImageWriter_LisaEm_Init(v);                 // &ADMP,pcl,ps,xlib
5386         DEBUG_LOG(0, "Attached ADMP to VIA#%d", v);
5387         return;
5388 	} else via[v].ADMP=0;
5389 
5390 
5391     if (device.IsSameAs(_T("PROFILE"), false))
5392     {
5393         if (file->Len()==0)
5394         {
5395          static const wxString def[]={  _T("null"),_T("COPS"),
5396                             _T("lisaem-profile.dc42"),
5397                             _T("lisaem-s1h-profile.dc42"),
5398                             _T("lisaem-s1l-profile.dc42"),
5399                             _T("lisaem-s2h-profile.dc42"),
5400                             _T("lisaem-s2l-profile.dc42"),
5401                             _T("lisaem-s3h-profile.dc42"),
5402                             _T("lisaem-s3l-profile.dc42") };
5403 
5404          if (v>1 && v<9) *file =def[v];
5405          else return;
5406         }
5407 
5408 		strncpy(tmp,(file->fn_str()),MAXPATHLEN);
5409 	    ALERT_LOG(0, "Attempting to attach VIA#%d to profile %s", v, tmp);
5410         via[v].ProFile = (ProFileType *)malloc(sizeof(ProFileType));
5411         int i = profile_mount(tmp, via[v].ProFile);
5412         if (i) {
5413             free(via[v].ProFile);
5414             via[v].ProFile = NULL;
5415             ALERT_LOG(0, "Couldn't get profile because: %d",i);
5416         } else {
5417 			via[v].ProFile->vianum=v;
5418             ProfileReset(via[v].ProFile);
5419         }
5420     }
5421 }
5422 
5423 /*
5424  * Connect some (virtual) device to one of the serial ports. 0 is Serial A,
5425  * 1 is Serial B. A number of the parameters passed in may be modified by
5426  * this code.
5427  */
connect_device_to_serial(int port,FILE ** scc_port_F,uint8 * serial,wxString * setting,wxString * param,int * scc_telnet_port)5428 void connect_device_to_serial(int port, FILE **scc_port_F, uint8 *serial,
5429     wxString *setting, wxString *param, int *scc_telnet_port)
5430 {
5431 	char cstr_param[MAXPATHLEN];
5432 	strncpy(cstr_param,param->fn_str(),MAXPATHLEN);
5433 
5434     if (port !=0 && port != 1) {
5435         DEBUG_LOG(0, "Warning Serial port is not A/B: %d", port);
5436         return;
5437     }
5438 
5439     if (setting->IsSameAs(_T("LOOPBACK"),false)) {
5440         *scc_port_F = NULL;
5441         *serial = SCC_LOOPBACKPLUG;
5442         return;
5443     }
5444 
5445     if (setting->IsSameAs(_T("NOTHING"), false) || setting->IsSameAs(_T("NULL"), false) || setting->Len()==0) {
5446         *scc_port_F = NULL;
5447         *serial = SCC_NOTHING;
5448         *setting = _T("NOTHING");  // fill in for writing into ini file
5449         return;
5450     }
5451 
5452     if (setting->IsSameAs(_T("FILE"), false))
5453     {
5454         *scc_port_F = fopen(cstr_param, "r+b");
5455         if (!*scc_port_F) {
5456             wxString err = wxString();
5457             err.Printf(_T("Could not map Serial port %c to file %s"), (port==0?'A':'B'), cstr_param);
5458             wxMessageBox(err, _T("Serial port configuration"),  wxICON_INFORMATION | wxOK);
5459             *scc_port_F = NULL;
5460             *serial = SCC_NOTHING;
5461         } else {
5462             *serial = SCC_FILE;
5463         }
5464         return;
5465     }
5466 
5467     if (setting->IsSameAs(_T("PIPE"), false)) {
5468         *scc_port_F = popen(cstr_param, "r+b");
5469         if (!*scc_port_F) {
5470             wxString err = wxString();
5471             err.Printf(_T("Could not map Serial port %c to pipe %s"), (port==0?'A':'B'), cstr_param);
5472             wxMessageBox(err, _T("Serial port configuration"),  wxICON_INFORMATION | wxOK);
5473             *scc_port_F = NULL;
5474             *serial = SCC_NOTHING;
5475         } else {
5476             *serial = SCC_PIPE;
5477         }
5478         return;
5479     }
5480 
5481 #ifndef __MSVCRT__
5482     if (setting->IsSameAs(_T("TELNETD"), false)) {
5483         unsigned long x;
5484         *scc_port_F = NULL;
5485         *serial = SCC_TELNETD;
5486 
5487         *scc_telnet_port = (param->ToULong(&x, 10)==false) ? 9300+port : x;
5488         ALERT_LOG(0,"Connecting TELNETD 127.0.0.1:%d on serial port %d",*scc_telnet_port,port);
5489 
5490         init_telnet_serial_port(!port);     // serial a=port 1, serial b=port 0 (reversed from config!)
5491         ALERT_LOG(0,"return from init_telnet_serial_port %d",port);
5492 
5493         return;
5494     }
5495 #endif
5496 
5497     if (setting->IsSameAs(_T("IMAGEWRITER"), false)) {
5498         *scc_port_F = NULL;
5499         *serial = SCC_IMAGEWRITER_PS;
5500         if (port) scc_b_IW=1; else scc_a_IW=0;
5501         ImageWriter_LisaEm_Init(port);
5502         return;
5503     }
5504 
5505 	strncpy(cstr_param,setting->fn_str(),MAXPATHLEN);
5506     DEBUG_LOG(0, "Warning: unrecognised Serial %c setting '%s'", port==0?'A':'B', cstr_param);
5507 }
5508 
romlessboot_pick(void)5509 int romlessboot_pick(void)
5510 {
5511  int r;
5512  wxString choices[]={
5513 	                     wxT( "ProFile Hard Drive on Parallel Port"),
5514                          wxT( "Floppy Diskette")
5515                     };
5516 
5517  wxString txt;
5518  wxSingleChoiceDialog *d=NULL;
5519  txt.Printf(_T("Which device should the virtual Lisa boot from?"));
5520 
5521  // if the parallel port device is a profile, offer a choice between the floppy and the profile
5522  if ( my_lisaconfig->parallel.IsSameAs(_T("PROFILE"), false) )
5523  {
5524 
5525  d=new wxSingleChoiceDialog(my_lisaframe,
5526                         txt,
5527                         wxT("ROMless Boot"),
5528                         2,             choices);
5529 
5530  if (d->ShowModal()==wxID_CANCEL) {delete d; return -1;}
5531  r=d->GetSelection();
5532  }
5533  else r=1;  // if not a profile, just boot from the floppy drive.
5534 
5535  if (r==1)   // if there's no floppy inserted, ask for one.
5536     {
5537 	  const char *s;
5538 	  if (!my_lisaframe->floppy_to_insert.Len()) my_lisaframe->OnxFLOPPY();
5539 	  if (!my_lisaframe->floppy_to_insert.Len()) return -1;  // if the user hasn't picked a floppy, abort.
5540       s = my_lisaframe->floppy_to_insert.fn_str();
5541       int i=floppy_insert((char *)s);
5542       wxMilliSleep(100);  // wait for insert sound to complete to prevent crash.
5543       if (i) { eject_floppy_animation(); return -1;}
5544       my_lisaframe->floppy_to_insert=_T("");
5545    	}
5546 
5547  delete d;
5548  return r;
5549 }
5550 
5551 
initialize_all_subsystems(void)5552  int initialize_all_subsystems(void)
5553  {
5554    /*
5555    In the beginning there was data.  The data was without form and null,
5556    and darkness was upon the face of the console; and the Spirit of IBM
5557    was moving over the face of the market.  And DEC said, "Let there be
5558    registers"; and there were registers.  And DEC saw that they carried;
5559    and DEC separated the data from the instructions.  DEC called the data
5560    Stack, and the instructions they called Code.  And there was evening
5561    and there was morning, one interrupt.         -- Rico Tudor            */
5562 
5563    int pickprofile=-1;
5564    char tmp[MAXPATHLEN];
5565 
5566        if (my_lisaframe->running) {ALERT_LOG(0,"Already running!");
5567                                    return 0;}
5568        buglog=stderr;
5569 
5570        setstatusbar("initializing all subsystems...");
5571 
5572        // initialize parity array (it's 2x faster to use an array than to call the fn)
5573        setstatusbar("Initializing Parity calculation cache array...");
5574        {uint16 i;
5575        for (i=0; i<256; i++) eparity[i]=evenparity((uint8) i);
5576        }
5577 
5578        segment1=0; segment2=0; start=1;
5579 
5580        // needs to be above read_config_files
5581        scc_a_port=NULL;
5582        scc_b_port=NULL;
5583        scc_a_IW=-1;
5584        scc_b_IW=-1;
5585        serial_a=0;
5586        serial_b=0;
5587 
5588        init_floppy(my_lisaconfig->iorom);
5589 
5590        bitdepth=8;                             // have to get this from the X Server side...
5591 
5592 
5593        DEBUG_LOG(0,"serial number");
5594        serialnum[0]=0x00;                      // "real" ones will be loaded from the settings file
5595        serialnum[1]=0x00;
5596        serialnum[2]=0x00;
5597        serialnum[3]=0x00;
5598        serialnum[4]=0x00;
5599        serialnum[5]=0x00;
5600        serialnum[6]=0x00;
5601        serialnum[7]=0x00;
5602        serialnumshiftcount=0; serialnumshift=0;
5603 
5604 
5605        // Is there no explicit way to init the COPS?
5606        DEBUG_LOG(0,"copsqueue");
5607        init_cops();
5608 
5609 
5610        setstatusbar("Initializing irq handlers");
5611        init_IRQ();
5612 
5613 
5614        setstatusbar("Initializing vias");
5615        init_vias();
5616 
5617 
5618        setstatusbar("Initializing profile hd's");
5619        init_Profiles();
5620 
5621 
5622        setstatusbar("Initializing Lisa RAM");
5623        TWOMEGMLIM=0x001fffff;
5624 
5625       // Simulate physical Lisa memory boards
5626       switch(my_lisaconfig->mymaxlisaram)
5627       {
5628        case 512  : maxlisaram=0x100000;  minlisaram=0x080000;  break;     // single 512KB board in slot 1
5629        case 1024 : maxlisaram=0x180000;  minlisaram=0x080000;  break;     // two 512KB boards in slot1, slot 2
5630        case 1536 : maxlisaram=0x200000;  minlisaram=0x080000;  break;     // 512KB board in slot1, 1024KB board in slot 2
5631        default:    maxlisaram=0x200000;  minlisaram=0x000000;  break;     // two 1024KB boards in slot 1,2
5632       }
5633 
5634        // maxlisaram! New!  And! Improved! Now available in bytes at a register Store Near You!  OpCodes are Standing by!
5635        // Act now!  don't delay!  Limited Time Offer!  JSR Now!  Restrictions Apply!  Before engaging in any strenous programming
5636        // activity, you should always consult your MMU today!  Not 0xFD1C insured!
5637 
5638 
5639       TWOMEGMLIM=maxlisaram-1;
5640    videolatchaddress=maxlisaram-0x10000;
5641 
5642    videolatch=(maxlisaram>>15)-1; // last page of ram is by default what the video latch gets set to.
5643    lastvideolatch=videolatch;  lastvideolatchaddress=videolatchaddress;
5644 
5645    if (lisaram) free(lisaram);          // remove old junk if it exists
5646 
5647    lisaram=(uint8 *)malloc(maxlisaram+512);     // added 512 bytes at the end to avoid overflows.
5648    if (!lisaram) {
5649        wxMessageBox(_T("Could not allocate memory for the Lisa to use."),
5650                     _T("Out of Memory!"), wxICON_INFORMATION | wxOK);
5651        return 23;
5652    }
5653 
5654    memset(lisaram,0xff,maxlisaram+512);
5655 
5656    if (my_lisaconfig->kbid) set_keyboard_id(my_lisaconfig->kbid);  else set_keyboard_id(-1);
5657 
5658     setstatusbar("Initializing Lisa Serial Number");
5659     // Parse sn and correct if needed  ////////////////////////////////////////////////////////////////////////////////////////
5660 	{
5661 
5662 		char cstr[32];
5663         //char mybuffer[5];
5664         int i,j; char c;
5665 		strncpy(cstr,my_lisaconfig->myserial.fn_str(),32);
5666 		char *s=cstr;
5667         for (i=0; (c=s[i]); i++)  {if ( !ishex(c) ) my_lisaconfig->myserial.Printf(_T("%s"),LISA_CONFIG_DEFAULTSERIAL); break;}
5668 
5669         if (i<31) DEBUG_LOG(1,"Warning: serial # less than 32 bytes (%d)!\n",i);
5670 
5671         for (i=0,j=0; i<32; i+=2,j++)
5672                 serialnum240[j]=(gethex(s[i])<<4)|gethex(s[i|1]);
5673 
5674         vidfixromchk(serialnum240);
5675 
5676         my_lisaconfig->myserial.Printf(_T("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"),
5677                         serialnum240[0],                 serialnum240[1],
5678                         serialnum240[2],                 serialnum240[3],
5679                         serialnum240[4],                 serialnum240[5],
5680                         serialnum240[6],                 serialnum240[7],
5681                         serialnum240[8],                 serialnum240[9],
5682                         serialnum240[10],                serialnum240[11],
5683                         serialnum240[12],                serialnum240[13],
5684                         serialnum240[14],                serialnum240[15]);
5685 
5686 //        ALERT_LOG(0,"Serial # used: %s", my_lisaconfig->myserial.c_str());
5687                                   //ff028308104050ff 0010163504700000
5688 
5689     }//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
5690 
5691     setstatusbar("Initializing Serial Ports");
5692 
5693     // If either serial port is set as loopback, both must be.
5694     if (my_lisaconfig->serial2_setting.IsSameAs(_T("LOOPBACK"), false) ||
5695         my_lisaconfig->serial1_setting.IsSameAs(_T("LOOPBACK"), false))
5696         {
5697           my_lisaconfig->serial1_setting = _T("LOOPBACK");
5698           my_lisaconfig->serial2_setting = _T("LOOPBACK");
5699         }
5700 
5701 
5702     connect_device_to_serial(0, &scc_a_port_F, &serial_a,
5703         &my_lisaconfig->serial1_setting, &my_lisaconfig->serial1_param,
5704         &scc_a_telnet_port);
5705 
5706 
5707     connect_device_to_serial(1, &scc_b_port_F, &serial_b,
5708         &my_lisaconfig->serial2_setting, &my_lisaconfig->serial2_param,
5709         &scc_b_telnet_port);
5710 
5711     DEBUG_LOG(0,"Initializing SCC Z8530");
5712     initialize_scc();
5713 
5714   DEBUG_LOG(0,"setting motherboard latches");
5715   softmemerror=0; harderror=0; videoirq=0; bustimeout=0; videobit=0;
5716 
5717   DEBUG_LOG(0,"Checking host CPU bit order sanity.");
5718   reg68k_sanity_check_bitorder();
5719 
5720   if (sizeof(XTIMER)<8) { wxMessageBox(_T("XTIMER isn't int64!."),
5721 									   _T("Danger!"), wxICON_INFORMATION | wxOK);  return 24; }
5722 
5723 
5724 
5725   setstatusbar("Initializing Generator CPU functions.");
5726   cpu68k_init();
5727 
5728   setstatusbar("Initializing MMU");
5729   init_lisa_mmu();
5730 
5731   setstatusbar("Initializing Generator CPU IPC Allocator");
5732   init_ipct_allocator();
5733 
5734   setstatusbar("Initializing Lisa Boot ROM");
5735 
5736   DEBUG_LOG(0,"Loading Lisa ROM");
5737   strncpy(tmp,my_lisaconfig->rompath.fn_str(),MAXPATHLEN);
5738   if      (read_dtc_rom(tmp,   lisarom)==0)
5739            {
5740             if (checkromchksum())
5741                {
5742                 if (!yesnomessagebox("BOOT ROM checksum doesn't match, this may crash the emulator.  Continue anyway?",
5743                                      "ROM Checksum mismatch"))   return -2;
5744                }
5745              DEBUG_LOG(0,"Load of DTC assembled ROM successful");
5746              fixromchk();
5747            }
5748   else if (read_split_rom(tmp, lisarom)==0)
5749            {
5750             if (checkromchksum())
5751                {
5752                 if (!yesnomessagebox("BOOT ROM checksum doesn't match, this may crash the emulator.  Continue anyway?",
5753                                      "ROM Checksum mismatch")  ) return -2;
5754                }
5755 
5756               DEBUG_LOG(0,"Load of split ROM");
5757               fixromchk();
5758            }
5759   else if (read_rom(tmp,       lisarom)==0)
5760            {
5761             if (checkromchksum())
5762                {
5763                 if (!yesnomessagebox("BOOT ROM checksum doesn't match, this may crash the emulator.  Continue anyway?",
5764                                      "ROM Checksum mismatch")  ) return -2;
5765                }
5766 
5767               DEBUG_LOG(0,"Load of normal ROM successful");
5768               fixromchk();
5769            }
5770   else
5771        {
5772          romless=1;
5773          pickprofile=romlessboot_pick(); if (pickprofile<0) return -2;
5774 		 ALERT_LOG(0,"picked %d",pickprofile);
5775        }
5776 
5777   setstatusbar("Initializing Lisa Display");
5778   if (has_xl_screenmod())
5779   {
5780 
5781    // This warning flag isn't really a configuration setting as such, but leave it here for the moment
5782    // the purpose of the flag is to prevent nagging the user.  So we only show the 3A warning the first time
5783    if (!my_lisaconfig->saw_3a_warning)
5784    wxMessageBox(_T("This is the XL Screen Modification ROM! You will only be able to run MacWorks."),
5785                     _T("3A ROM!"),   wxICON_INFORMATION | wxOK);
5786 
5787 
5788    my_lisaconfig->saw_3a_warning=1;
5789    lisa_vid_size_x=608;
5790    lisa_vid_size_y=431;
5791    effective_lisa_vid_size_x=608;
5792    effective_lisa_vid_size_y=431;
5793 
5794    screen_origin_x=140+56;
5795    screen_origin_y=130+34;
5796 
5797    lisa_vid_size_x=608;
5798    lisa_vid_size_y=431;
5799 
5800    lisa_vid_size_xbytes=76;
5801    has_lisa_xl_screenmod=1;
5802 
5803    setvideomode(0x3a);
5804   }
5805   else
5806   {
5807    lisa_vid_size_x=720;
5808    lisa_vid_size_y=364;
5809    effective_lisa_vid_size_x=720;
5810    effective_lisa_vid_size_y=500;
5811 
5812    screen_origin_x=140;
5813    screen_origin_y=130;
5814 
5815    lisa_vid_size_x=720;
5816    lisa_vid_size_y=364;
5817 
5818 
5819    lisa_vid_size_xbytes=90;
5820    has_lisa_xl_screenmod=0;
5821 
5822    setvideomode(lisa_ui_video_mode);
5823 
5824 
5825   }
5826 
5827   ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
5828 
5829   setstatusbar("Initializing Parallel Port");
5830   // Handle Parallel Ports
5831 
5832   // Connect profile/printer to builtin parallel port
5833   connect_device_to_via(2, my_lisaconfig->parallel, &my_lisaconfig->parallelp);
5834 
5835   // ----------------------------------------------------------------------------------
5836 
5837   // Dual Parallel Port Expansion Cards
5838 
5839   setstatusbar("Initializing Expansion Card Slots");
5840   memset(dualparallelrom,0xff,2048);
5841 
5842   strncpy(tmp,my_lisaconfig->dualrom.fn_str(),MAXPATHLEN);
5843   if (read_parallel_card_rom(tmp)==0)
5844      {
5845   	    ALERT_LOG(0,"Connecting Dual Parallel Port Cards.");
5846 
5847         if (my_lisaconfig->slot1.IsSameAs(_T("dualparallel"),false) )
5848           {
5849   			    ALERT_LOG(0,"Connecting slot 1");
5850                   connect_2x_parallel_to_slot(0);
5851                   connect_device_to_via(3, my_lisaconfig->s1h, &my_lisaconfig->s1hp);
5852                   connect_device_to_via(4, my_lisaconfig->s1l, &my_lisaconfig->s1lp);
5853           }
5854 
5855         if (my_lisaconfig->slot2.IsSameAs(_T("dualparallel"),false) )
5856           {
5857   		        ALERT_LOG(0,"Connecting slot 2");
5858                   connect_2x_parallel_to_slot(1);
5859                   connect_device_to_via(5, my_lisaconfig->s2h, &my_lisaconfig->s2hp);
5860                   connect_device_to_via(6, my_lisaconfig->s2l, &my_lisaconfig->s2lp);
5861           }
5862 
5863 
5864         if (my_lisaconfig->slot3.IsSameAs(_T("dualparallel"),false))
5865           {
5866   		        ALERT_LOG(0,"Connecting slot 3");
5867                   connect_2x_parallel_to_slot(2);
5868                   connect_device_to_via(7, my_lisaconfig->s3h, &my_lisaconfig->s3hp);
5869                   connect_device_to_via(8, my_lisaconfig->s3l, &my_lisaconfig->s3lp);
5870           }
5871 
5872 
5873      }
5874 
5875 
5876     ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
5877 
5878     ALERT_LOG(0,"initializing video");
5879     disable_vidram(); videoramdirty=32768;
5880 
5881     ALERT_LOG(0,"Calling Redraw Pixels");
5882     LisaRedrawPixels();
5883 
5884     setstatusbar("Initializing CPU Registers");
5885     cpu68k_reset();
5886 
5887     ALERT_LOG(0,"done initializing...");
5888 
5889 //    debug_off();
5890 
5891     setstatusbar("Executing Lisa Boot ROM");
5892     refresh_rate_used=refresh_rate;       // powering (back) on, so use the user selected refresh rate.
5893     my_lisaframe->reset_throttle_clock();
5894     my_lisawin->Refresh(false,NULL); //
5895     // needs to be at the end since romless_boot sets up registers which get whacked by the cpu initialization
5896 
5897     if (romless)
5898        {
5899            if (pickprofile) wxMilliSleep(1000);
5900 		   if (romless_boot(pickprofile) ) return 1; // failed
5901 
5902 //         // has to be here since romless_boot overwrites low memory
5903   		   storeword(0x298, my_lisaconfig->slot1.IsSameAs(_T("dualparallel"),false) ? (dualparallelrom[0]<<8)|dualparallelrom[1]  : 0);
5904  		   storeword(0x29a, my_lisaconfig->slot2.IsSameAs(_T("dualparallel"),false) ? (dualparallelrom[0]<<8)|dualparallelrom[1]  : 0);
5905  		   storeword(0x29c, my_lisaconfig->slot3.IsSameAs(_T("dualparallel"),false) ? (dualparallelrom[0]<<8)|dualparallelrom[1]  : 0);
5906       }
5907 
5908     return 0;
5909 } ///////////////////// end of load.///////////////////
5910 
5911 
5912 
5913  // just to be a bastard!  why? because split roms are a lame result of dumping ROMs from a ROM reader.
5914  // otherwise we have to merge it every time we boot up. :-)
rename_rompath(char * rompath)5915  extern "C" void rename_rompath(char *rompath)
5916  {
5917    if (!my_lisaconfig)  return;
5918 
5919    my_lisaconfig->rompath=wxString(rompath, wxConvLocal, 2048); //wxSTRING_MAXLEN);
5920    my_lisaconfig->Save(pConfig, floppy_ram);
5921 
5922    if (my_LisaConfigFrame) my_LisaConfigFrame->m_rompath->SetValue(my_lisaconfig->rompath);
5923    DEBUG_LOG(0,"saved %s as default\n",rompath);
5924  }
5925 
force_refresh(void)5926 extern "C" void force_refresh(void)                    //20060202.;
5927 {
5928             my_lisaframe->Refresh(false,NULL);
5929            // my_lisaframe->Update();
5930 }
5931 
save_pram(void)5932 extern "C" void save_pram(void)
5933 {
5934  my_lisaconfig->Save(pConfig, floppy_ram);// save it so defaults are created
5935 }
5936 
invalidate_configframe(void)5937 void invalidate_configframe(void) {my_LisaConfigFrame=NULL;}
5938 
5939 
save_configs(void)5940 extern "C" void save_configs(void)
5941 {
5942   my_lisaconfig->Save(pConfig, floppy_ram);// save it so defaults are created
5943   save_global_prefs();
5944 }
5945 
5946 
5947             //               0     1     2     3     4     5     6
5948             //              5M   10M   16M   20M   32M   40M    64M
pickprofilesize(char * filename)5949 extern "C" int pickprofilesize(char *filename)
5950 {
5951  wxString choices[]={    wxT( "5M - any OS"),
5952                          wxT("10M - any OS"),
5953                          wxT("16M - MacWorks only"),
5954                          wxT("20M - MacWorks only"),
5955                          wxT("32M - MacWorks only"),
5956                          wxT("40M - MacWorks only"),
5957                          wxT("64M - MacWorks only") };
5958 
5959  wxSingleChoiceDialog *d;
5960 
5961  wxString txt=wxString(filename, wxConvLocal, 2048); //wxSTRING_MAXLEN);
5962 
5963  txt+=_T(" does not yet exist.  What size drive should I create?");
5964 
5965  d=new wxSingleChoiceDialog(my_lisaframe,
5966                            txt,
5967                            _T("Hard Drive Size?"),
5968                            7,             choices);
5969 
5970  if (d->ShowModal()==wxID_CANCEL) {delete d; return -1;}
5971 
5972  int r=d->GetSelection();
5973  delete d;
5974  return r;
5975 }
5976 
5977 
5978 
5979 
5980 // bridge to LisaConfigFrame to let it know what config file is opened.
get_config_filename(void)5981 wxString get_config_filename(void)  { return myconfigfile;}
5982 
5983 
turn_skins_on(void)5984 void turn_skins_on(void)   {
5985                              skins_on_next_run=1;
5986                              skins_on=1;
5987                              save_global_prefs();
5988                              my_lisaframe->LoadImages();
5989                              setvideomode(lisa_ui_video_mode);
5990                              black();
5991                              screen_origin_x=140;
5992                              screen_origin_y=130;
5993                            }
5994 
turn_skins_off(void)5995 void turn_skins_off(void)  {
5996                              skins_on_next_run=0;
5997                              skins_on=0;
5998                              save_global_prefs();
5999                              my_lisaframe->UnloadImages();
6000                              setvideomode(lisa_ui_video_mode);
6001                              black();
6002 							}
6003 
6004 
6005 
contrastchange(void)6006 extern "C" void contrastchange(void) {my_lisawin->ContrastChange();}
6007 
setvideomode(int mode)6008 void setvideomode(int mode) {my_lisawin->SetVideoMode(mode);}
6009 
6010 
6011 
6012 //----- ImageWriter interfaces to old C code. -----//
6013 
6014 
6015 
6016 #include "imagewriter-wx.h"
6017 
6018 ImageWriter *imagewriter[10];           // two serial ports, one parallel, 6 max dual parallel port cards, 9 possible
6019 
6020 
ImageWriter_LisaEm_Init(int iwnum)6021 extern "C" int ImageWriter_LisaEm_Init(int iwnum)
6022 {
6023  if (iwnum>10) return -1;
6024  if (imagewriter[iwnum]!=NULL) return 0; // already built, reuse it;
6025  imagewriter[iwnum]=new ImageWriter(my_lisaframe,
6026                                     my_lisaconfig->iw_png_on,
6027                                     my_lisaconfig->iw_png_path,
6028                                     my_lisaconfig->iw_dipsw_1);
6029 
6030  imagewriter[iwnum]->iwid=iwnum;         // set printer ID
6031 
6032 // imagewriter[iwnum]->test(); // spit out a set of test pages.
6033 
6034  return 0;
6035 }
6036 
iw_shutdown(void)6037 extern "C" void iw_shutdown(void)
6038 {
6039   int i;
6040   for (i=0; i<10; i++) if (imagewriter[i]!=NULL) {delete imagewriter[i]; imagewriter[i]=NULL;}
6041 }
6042 
iw_formfeed(int iw)6043 extern "C" void iw_formfeed(int iw)              {if (iw<10 && iw>-1 && imagewriter[iw]) imagewriter[iw]->iw_formfeed();     }
ImageWriterLoop(int iw,uint8 c)6044 extern "C" void ImageWriterLoop(int iw,uint8 c)  {if (iw<10 && iw>-1 && imagewriter[iw]) imagewriter[iw]->ImageWriterLoop(c);}
iw_enddocument(int i)6045 extern "C" void iw_enddocument(int i)
6046 {
6047   if (i<0 || i>10) return;
6048   if (imagewriter[i]!=NULL) {imagewriter[i]->EndDocument();}
6049 }
6050 
iw_enddocuments(void)6051 extern "C" void iw_enddocuments(void)
6052 {
6053   int i;
6054   for (i=2; i<10; i++)
6055       if (imagewriter[i]!=NULL)
6056 	       imagewriter[i]->EndDocument();
6057 
6058   for (i=2; i<10; i++) via[i].last_pa_write=-1;
6059 
6060  }
6061 
6062 // if any printer job has lingered for more than X seconds, flush that printer.
iw_check_finish_job(void)6063 void iw_check_finish_job(void)
6064 {
6065   int i;
6066   for (i=2; i<10; i++)
6067 	  if (imagewriter[i]!=NULL)
6068        {
6069 	    if ((cpu68k_clocks - via[i].last_pa_write > FIFTEEN_SECONDS) || via[i].last_pa_write==-1)
6070 	       {
6071 			 #ifdef DEBUG
6072 			 ALERT_LOG(0,"No activity on printer #%d - flushing page",i);
6073 			 #endif
6074 	         via[i].last_pa_write=-1;
6075 	         imagewriter[i]->EndDocument();  // ensure no stray data left queued up
6076 	       }
6077        }
6078 }
6079 
6080 
6081 
6082 void uninit_gui(void);
6083 
6084 // from generator
6085 unsigned int gen_quit = 0;
6086 unsigned int gen_debugmode = 1;
6087 
6088 
6089 
6090 
6091 
6092 
6093 #ifdef DEBUG
6094 void    dumpallmmu(void);
6095 #endif
6096 void    dumpvia(void);
6097 
6098 /////------------------------------------------------------------------------------------------------------------------------
6099 
6100 
banner(void)6101 void banner(void)
6102 {
6103 
6104  //         .........1.........2.........3.........4.........5.........6.........7
6105  //         123456789012345678901234567890123456789012345678901234567890123456789012345678
6106     printf("\n\n");
6107     printf("-----------------------------------------------------------------------\n");
6108 #ifdef VERSION
6109     printf("  The Lisa II Emulator   %-17s   http://lisaem.sunder.net  \n",my_version);
6110 #else
6111     printf("  The Lisa II Emulator   %-17s   http://lisaem.sunder.net  \n","UNKNOWN");
6112 #endif
6113     printf("  -------------------------------------------------------------------  \n");
6114     printf("  Copyright  (C)   MMVII  by Ray A. Arachelian,   All Rights Reserved  \n");
6115     printf("  Released  under  the terms of  the  GNU Public License  Version 2.0  \n");
6116     printf("  -------------------------------------------------------------------  \n");
6117     printf("  For historical/archival/educational use only - no warranty provied.  \n");
6118     printf("  -------------------------------------------------------------------  \n");
6119     printf("  Portions of this software contain bits of code from the following:   \n");
6120     printf("  generator - www.squish.net/generator  wxWidgets.org  - www.ijg.org   \n");
6121     printf("   Many thanks to David T. Craig for the tons of Lisa documentation    \n");
6122     printf("     Many thanks to James McPhail for Lisa and 68000 hardware help     \n");
6123 	printf("      Many thanks to Brain Folley for the OS X UI help                 \n");
6124     printf("-----------------------------------------------------------------------\n\n");
6125 
6126 #ifdef DEBUG
6127     printf("\nDEBUG is compiled in.\n");
6128     fprintf(buglog,"\nDEBUG is compiled in.\n");
6129 #endif
6130 
6131 #ifdef DEBUGMEMCALLS
6132     printf("\nDEBUGMEMCALLS is enabled.\n");
6133     fprintf(buglog,"\nDEBUGMEMCALLS is enabled.\n");
6134     ALERT_LOG(0,"DEBUGMEMCALLS is on.");
6135 #endif
6136 }
6137 
6138 
6139 
6140 //uint8 evenparity(uint8 data)          // naive way
6141 //{ return  !( (   (data & 0x01) ? 1:0) ^
6142 //             (   (data & 0x02) ? 1:0) ^
6143 //             (   (data & 0x04) ? 1:0) ^
6144 //             (   (data & 0x08) ? 1:0) ^
6145 //             (   (data & 0x10) ? 1:0) ^
6146 //             (   (data & 0x20) ? 1:0) ^
6147 //             (   (data & 0x40) ? 1:0) ^
6148 //             (   (data & 0x80) ? 1:0)   );}
6149 //
6150 
evenparity(uint8 data)6151 uint8 evenparity(uint8 data)            // from http://graphics.stanford.edu/~seander/bithacks.html#ParityParallel
6152 {
6153  uint32 v=data;
6154 //v ^= v >> 16;       // not needed since we're working on a byte - only here for completeness, but commented out
6155 //v ^= v >> 8;        // ditto
6156   v ^= v >> 4;
6157   v &= 0xf;
6158   return !(  (0x6996 >> v) & 1  );
6159 }
6160 
oddparity(uint8 data)6161 uint8 oddparity(uint8 data)            // from BitTwiddling hacks.
6162 {
6163  uint32 v=data;
6164 
6165  v ^= v >> 4;
6166  v &= 0xf;
6167 
6168  return (  (0x6996 >> v) & 1  );
6169 }
6170 
6171 
6172 
6173 
6174 // This redraws the lisa display ram into the Ximage
6175 // If you are porting to another OS, this is one of
6176 // the functions to replace.  This is slow, so it should be called as rarely as possible.
6177 // i.e. only when the Lisa switches video screens by changing videolatch
6178 
6179 extern "C" void XLLisaRedrawPixels(void);          // proto to supress warning below
6180 extern "C" void LisaRedrawPixels(void);
6181 
6182 
LisaRedrawPixels(void)6183 extern "C" void LisaRedrawPixels(void)
6184 {
6185  my_lisawin->repaintall |= REPAINT_VIDEO_TO_SKIN;
6186  my_lisawin->Refresh(false,NULL);
6187  //my_lisawin->Update();
6188 }
6189 
6190 #ifdef __cplusplus
6191 extern "C"
6192 #endif
LisaScreenRefresh(void)6193 void LisaScreenRefresh(void)
6194 {
6195  LisaRedrawPixels();
6196 }
6197 
6198 
6199 
6200 static float normalthrottle=0;
6201 
sound_off(void)6202 extern "C" void sound_off(void)
6203 {
6204 	// restore throttle
6205 	if (normalthrottle!=0)
6206 	{my_lisaframe->throttle=normalthrottle; updateThrottleMenus(my_lisaframe->throttle);}
6207 
6208     if (cpu68k_clocks-my_lisaframe->lastclk<50000) return;  // prevent sound from shutting down immediately
6209     wxSound::Stop();
6210 }
6211 
6212 
6213 
sound_play(uint16 t2)6214 extern "C" void sound_play(uint16 t2)
6215 {
6216 
6217     // temporarily slow down CPU durring beeps so that they're fully played.
6218 	normalthrottle=my_lisaframe->throttle; updateThrottleMenus(5.0);
6219 
6220 
6221     int samples=22050*2;                // a second
6222 
6223 
6224     int data_size=0;
6225     int cycles, halfcycles;
6226     unsigned char vhigh, vlow; //, l;
6227 
6228 
6229     if (t2>0xaf) return;                                  // out of range
6230     if (my_lisaframe->lastt2==t2 && (cpu68k_clocks-my_lisaframe->lastclk < 50000)) return;  // duplicate call if timing <1/100th of a second
6231 
6232     my_lisaframe->lastt2=t2;
6233     my_lisaframe->lastclk=cpu68k_clocks;
6234 
6235 
6236     static const unsigned char header[45]=
6237     {
6238         // 0     1    2    3    4    5    6    7    8    9    a    b    c    d    e    f
6239 /*00*/  0x52,0x49,0x46,0x46,   0,   0,0x00,0x00,0x57,0x41,0x56,0x45,0x66,0x6D,0x74,0x20,  // RIFFF-..WAVEfmt
6240 /*10*/  0x10,0x00,0x00,0x00,   1,   0,0x01,0x00,0x22,0x56,0x00,0x00,0x22,0x56,0x00,0x00,  //  ........"V.."V..
6241 /*20*/  0x01,0x00,0x08,0x00,0x64,0x61,0x74,0x61,0x22,0x2D,0x00,0x00//0x80,0x80,0x80,0x80  //  ....data"-......
6242     };           //        d    a    t    a [LSB____________MSB]
6243 
6244     static unsigned char data[22050*5+45+1024];
6245     unsigned char *dataptr;
6246     //data=(unsigned char *)malloc(45+samples+1024);  // allocate a buffer, make it 22Kbps
6247     memcpy(data,header,45);        // copy the header over it.
6248 
6249 
6250     data[0x16]=1;      // 1=1 channel = mono, 2= 2 channels = stereo
6251     data[0x17]=0;
6252 
6253 
6254     data[0x18]=0x22;   // bit rate LSB.   0x5622=22050Hz   22Khz
6255     data[0x19]=0x56;   //                 0x2D22=11554Hz   11Khz
6256     data[0x1a]=0x00;   //                 0xAC44=44100Hz   44Khz
6257     data[0x1b]=0x00;   // bit rate MSB
6258 
6259 
6260     data[0x1c]=0x22;   // bytes per second
6261     data[0x1d]=0x56;   // should match bit rate for 8 bit samples
6262     data[0x1e]=0x00;
6263     data[0x1f]=0x00;
6264 
6265     data[0x20]=1;      // Bytes Per Sample:
6266     data[0x21]=0;      // 1=8 bit Mono, 2=8 bit Stereo or 16 bit Mono, 4=16 bit Stereo
6267 
6268     data[0x22]=8;      // 8, or 16  bits/sample
6269     data[0x23]=0;
6270 
6271     dataptr=&data[0x2c]; data_size=0;
6272 
6273     volume=(volume & 0x0f);
6274 
6275     vlow =128-(volume<<3);
6276     vhigh=128+(volume<<3);
6277 
6278     cycles=t2;
6279     if (!(my_lisaconfig->iorom & 0x20)) cycles=cycles*8/10;       // cycles *=0.8
6280     cycles=(cycles>>1)+(cycles>>2);                // cycles *=0.75; (1/2 + 1/4th)
6281     halfcycles=cycles>>1;                          // cycles /=2;
6282 
6283     int i=0;
6284     if (t2>0x90) samples=cycles;                   // prevent click from turning into beep
6285     while (samples>=cycles)
6286     {
6287         i++;
6288      memset(dataptr,vhigh,halfcycles); dataptr+=halfcycles;
6289      memset(dataptr,vlow, halfcycles); dataptr+=halfcycles;
6290      samples-=cycles; data_size+=cycles;
6291     }
6292 
6293     data[0x28]=((data_size)    ) & 0xff;
6294     data[0x29]=((data_size)>>8 ) & 0xff;
6295     data[0x2a]=((data_size)>>16) & 0xff;
6296     data[0x2b]=((data_size)>>24) & 0xff;
6297 
6298     data[0x04]=((data_size+36)    ) & 0xff;
6299     data[0x05]=((data_size+36)>>8 ) & 0xff;
6300     data[0x06]=((data_size+36)>>16) & 0xff;
6301     data[0x07]=((data_size+36)>>24) & 0xff;
6302 
6303 
6304     dataptr=&data[0];
6305 
6306     if (my_lisa_sound!=NULL) delete my_lisa_sound;
6307     my_lisa_sound=new wxSound;  //my_lisa_sound->Create(dataptr,data_size);
6308 
6309     // this should work, but it doesn't on all platforms
6310     //my_lisa_sound->Create(data_size,dataptr);
6311     //my_lisa_sound->Play(wxSOUND_ASYNC);
6312 
6313     // so instead, use the super lame ass way to play a sound
6314     FILE *f;
6315     f=fopen("tmpsnd.wav","wb");
6316     if (f) {
6317              fwrite(dataptr,data_size+45,1,f); fclose(f);
6318              my_lisa_sound->Create(_T("tmpsnd.wav"),false);
6319              // we do not check for sound_effects_on here as this is the Lisa beeping.
6320              my_lisa_sound->Play(wxSOUND_ASYNC);
6321              unlink("tmpsnd.wav");
6322            }
6323     errno=0;  // avoid interfearance with other stuff like libdc42.
6324     return;
6325 }
6326 
6327 
6328 
6329