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