ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/BeOS/video_beos.cpp
Revision: 1.5
Committed: 2001-02-02T20:52:57Z (23 years, 10 months ago) by cebix
Branch: MAIN
CVS Tags: snapshot-17022001
Changes since 1.4: +1 -1 lines
Log Message:
- bumped version number to 0.9
- updated copyright dates

File Contents

# Content
1 /*
2 * video_beos.cpp - Video/graphics emulation, BeOS specific stuff
3 *
4 * Basilisk II (C) 1997-2001 Christian Bauer
5 * Portions (C) 1997-1999 Marc Hellwig
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #include <AppKit.h>
23 #include <InterfaceKit.h>
24 #include <GameKit.h>
25
26 #include <stdio.h>
27 #include <string.h>
28
29 #include "sysdeps.h"
30 #include "cpu_emulation.h"
31 #include "main.h"
32 #include "macos_util.h"
33 #include "prefs.h"
34 #include "adb.h"
35 #include "prefs.h"
36 #include "user_strings.h"
37 #include "version.h"
38 #include "video.h"
39
40 #include "m68k.h"
41 #include "memory.h"
42 #include "readcpu.h"
43 #include "newcpu.h"
44 #include "compiler.h"
45
46 #define DEBUG 0
47 #include "debug.h"
48
49 #define DEBUGGER_AVAILABLE 0
50
51
52 // Messages
53 const uint32 MSG_REDRAW = 'draw';
54 const uint32 MSG_ABOUT_REQUESTED = B_ABOUT_REQUESTED;
55 const uint32 MSG_REF_5HZ = ' 5Hz';
56 const uint32 MSG_REF_7_5HZ = ' 7Hz';
57 const uint32 MSG_REF_10HZ = '10Hz';
58 const uint32 MSG_REF_15HZ = '15Hz';
59 const uint32 MSG_REF_30HZ = '30Hz';
60 const uint32 MSG_REF_60HZ = '60Hz';
61 const uint32 MSG_MOUNT = 'moun';
62 const uint32 MSG_DEBUGGER = 'dbug';
63
64 // Display types
65 enum {
66 DISPLAY_WINDOW,
67 DISPLAY_SCREEN
68 };
69
70 // From sys_beos.cpp
71 extern void SysCreateVolumeMenu(BMenu *menu, uint32 msg);
72 extern void SysMountVolume(const char *name);
73
74
75 /*
76 * A simple view class for blitting a bitmap on the screen
77 */
78
79 class BitmapView : public BView {
80 public:
81 BitmapView(BRect frame, BBitmap *bitmap) : BView(frame, "bitmap", B_FOLLOW_NONE, B_WILL_DRAW)
82 {
83 the_bitmap = bitmap;
84 }
85 virtual void Draw(BRect update)
86 {
87 DrawBitmap(the_bitmap, update, update);
88 }
89 virtual void MouseMoved(BPoint point, uint32 transit, const BMessage *message);
90
91 private:
92 BBitmap *the_bitmap;
93 };
94
95
96 /*
97 * Window class
98 */
99
100 class MacWindow : public BDirectWindow {
101 public:
102 MacWindow(BRect frame);
103 virtual ~MacWindow();
104 virtual void MessageReceived(BMessage *msg);
105 virtual void DirectConnected(direct_buffer_info *info);
106 virtual void WindowActivated(bool active);
107
108 int32 frame_skip;
109 bool mouse_in_view; // Flag: Mouse pointer within bitmap view
110 uint8 remap_mac_be[256]; // For remapping of Mac colors to Be colors
111
112 private:
113 static status_t tick_func(void *arg);
114
115 thread_id tick_thread;
116 bool tick_thread_active; // Flag for quitting the tick thread
117
118 BitmapView *main_view; // Main view for bitmap drawing
119 BBitmap *the_bitmap; // Mac screen bitmap
120 uint8 *the_buffer; // Mac frame buffer
121
122 uint32 old_scroll_lock_state;
123
124 bool supports_direct_mode; // Flag: Direct frame buffer access supported
125 sem_id drawing_sem;
126
127 void *bits;
128 int32 bytes_per_row;
129 color_space pixel_format;
130 bool unclipped;
131 };
132
133
134 /*
135 * Screen class
136 */
137
138 class MacScreen : public BWindowScreen {
139 public:
140 MacScreen(const char *name, int mode_bit, status_t *error);
141 virtual ~MacScreen();
142 virtual void Quit(void);
143 virtual void ScreenConnected(bool active);
144
145 rgb_color palette[256]; // Color palette, 256 entries
146 bool palette_changed;
147
148 private:
149 static status_t tick_func(void *arg);
150
151 thread_id tick_thread;
152 bool tick_thread_active; // Flag for quitting the tick thread
153
154 BView *main_view; // Main view for GetMouse()
155 uint8 *frame_backup; // Frame buffer backup when switching from/to different workspace
156 bool quitting; // Flag for ScreenConnected: We are quitting, don't pause emulator thread
157 bool screen_active;
158 };
159
160
161 // Global variables
162 static int display_type = DISPLAY_WINDOW; // See enum above
163 static MacWindow *the_window = NULL; // Pointer to the window
164 static MacScreen *the_screen = NULL; // Pointer to the screen
165 static sem_id mac_os_lock = -1; // This is used to stop the MacOS thread when the Basilisk workspace is switched out
166 static uint8 MacCursor[68] = {16, 1}; // Mac cursor image
167
168
169 /*
170 * Initialization
171 */
172
173 bool VideoInit(bool classic)
174 {
175 // Create semaphore
176 mac_os_lock = create_sem(0, "MacOS Frame Buffer Lock");
177
178 // Get screen mode from preferences
179 const char *mode_str = PrefsFindString("screen");
180
181 // Determine type and mode
182 display_type = DISPLAY_WINDOW;
183 int width = 512, height = 384;
184 int scr_mode_bit = 0;
185 if (mode_str) {
186 if (sscanf(mode_str, "win/%d/%d", &width, &height) == 2)
187 display_type = DISPLAY_WINDOW;
188 else if (sscanf(mode_str, "scr/%d", &scr_mode_bit) == 1)
189 display_type = DISPLAY_SCREEN;
190 }
191
192 // Open display
193 switch (display_type) {
194 case DISPLAY_WINDOW:
195 the_window = new MacWindow(BRect(0, 0, width-1, height-1));
196 break;
197 case DISPLAY_SCREEN: {
198 status_t screen_error;
199 the_screen = new MacScreen(GetString(STR_WINDOW_TITLE), scr_mode_bit & 0x1f, &screen_error);
200 if (screen_error != B_NO_ERROR) {
201 the_screen->PostMessage(B_QUIT_REQUESTED);
202 while (the_screen)
203 snooze(200000);
204 ErrorAlert(GetString(STR_OPEN_SCREEN_ERR));
205 return false;
206 } else {
207 the_screen->Show();
208 acquire_sem(mac_os_lock);
209 }
210 break;
211 }
212 }
213 return true;
214 }
215
216
217 /*
218 * Deinitialization
219 */
220
221 void VideoExit(void)
222 {
223 // Close display
224 switch (display_type) {
225 case DISPLAY_WINDOW:
226 if (the_window != NULL) {
227 the_window->PostMessage(B_QUIT_REQUESTED);
228 while (the_window)
229 snooze(200000);
230 }
231 break;
232 case DISPLAY_SCREEN:
233 if (the_screen != NULL) {
234 the_screen->PostMessage(B_QUIT_REQUESTED);
235 while (the_screen)
236 snooze(200000);
237 }
238 break;
239 }
240
241 // Delete semaphore
242 delete_sem(mac_os_lock);
243 }
244
245
246 /*
247 * Set palette
248 */
249
250 void video_set_palette(uint8 *pal)
251 {
252 switch (display_type) {
253 case DISPLAY_WINDOW: {
254 BScreen screen(the_window);
255 for (int i=0; i<256; i++)
256 the_window->remap_mac_be[i] = screen.IndexForColor(pal[i*3], pal[i*3+1], pal[i*3+2]);
257 break;
258 }
259 case DISPLAY_SCREEN:
260 for (int i=0; i<256; i++) {
261 the_screen->palette[i].red = pal[i*3];
262 the_screen->palette[i].green = pal[i*3+1];
263 the_screen->palette[i].blue = pal[i*3+2];
264 }
265 the_screen->palette_changed = true;
266 break;
267 }
268 }
269
270
271 /*
272 * Close down full-screen mode (if bringing up error alerts is unsafe while in full-screen mode)
273 */
274
275 void VideoQuitFullScreen(void)
276 {
277 D(bug("VideoQuitFullScreen()\n"));
278 if (display_type == DISPLAY_SCREEN) {
279 if (the_screen != NULL) {
280 the_screen->PostMessage(B_QUIT_REQUESTED);
281 while (the_screen)
282 snooze(200000);
283 }
284 }
285 }
286
287
288 /*
289 * Video event handling (not neccessary under BeOS, handled by filter function)
290 */
291
292 void VideoInterrupt(void)
293 {
294 release_sem(mac_os_lock);
295 while (acquire_sem(mac_os_lock) == B_INTERRUPTED) ;
296 }
297
298
299 /*
300 * Filter function for receiving mouse and keyboard events
301 */
302
303 #define MENU_IS_POWER 0
304
305 // Be -> Mac raw keycode translation table
306 static const uint8 keycode2mac[0x80] = {
307 0xff, 0x35, 0x7a, 0x78, 0x63, 0x76, 0x60, 0x61, // inv Esc F1 F2 F3 F4 F5 F6
308 0x62, 0x64, 0x65, 0x6d, 0x67, 0x6f, 0x69, 0x6b, // F7 F8 F9 F10 F11 F12 F13 F14
309 0x71, 0x0a, 0x12, 0x13, 0x14, 0x15, 0x17, 0x16, // F15 ` 1 2 3 4 5 6
310 0x1a, 0x1c, 0x19, 0x1d, 0x1b, 0x18, 0x33, 0x72, // 7 8 9 0 - = BSP INS
311 0x73, 0x74, 0x47, 0x4b, 0x43, 0x4e, 0x30, 0x0c, // HOM PUP NUM / * - TAB Q
312 0x0d, 0x0e, 0x0f, 0x11, 0x10, 0x20, 0x22, 0x1f, // W E R T Y U I O
313 0x23, 0x21, 0x1e, 0x2a, 0x75, 0x77, 0x79, 0x59, // P [ ] \ DEL END PDN 7
314 0x5b, 0x5c, 0x45, 0x39, 0x00, 0x01, 0x02, 0x03, // 8 9 + CAP A S D F
315 0x05, 0x04, 0x26, 0x28, 0x25, 0x29, 0x27, 0x24, // G H J K L ; ' RET
316 0x56, 0x57, 0x58, 0x38, 0x06, 0x07, 0x08, 0x09, // 4 5 6 SHL Z X C V
317 0x0b, 0x2d, 0x2e, 0x2b, 0x2f, 0x2c, 0x38, 0x3e, // B N M , . / SHR CUP
318 0x53, 0x54, 0x55, 0x4c, 0x36, 0x37, 0x31, 0x37, // 1 2 3 ENT CTL ALT SPC ALT
319 0x36, 0x3b, 0x3d, 0x3c, 0x52, 0x41, 0x3a, 0x3a, // CTR CLF CDN CRT 0 . CMD CMD
320 #if MENU_IS_POWER
321 0x7f, 0x32, 0x51, 0x7f, 0xff, 0xff, 0xff, 0xff, // MNU EUR = POW inv inv inv inv
322 #else
323 0x32, 0x32, 0x51, 0x7f, 0xff, 0xff, 0xff, 0xff, // MNU EUR = POW inv inv inv inv
324 #endif
325 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // inv inv inv inv inv inv inv inv
326 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff // inv inv inv inv inv inv inv inv
327 };
328
329 static const uint8 modifier2mac[0x20] = {
330 #if MENU_IS_POWER
331 0x38, 0x37, 0x36, 0x39, 0x6b, 0x47, 0x3a, 0x7f, // SHF CMD inv CAP F14 NUM OPT MNU
332 #else
333 0x38, 0x37, 0x36, 0x39, 0x6b, 0x47, 0x3a, 0x32, // SHF CMD CTR CAP F14 NUM OPT MNU
334 #endif
335 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // inv inv inv inv inv inv inv inv
336 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // inv inv inv inv inv inv inv inv
337 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff // inv inv inv inv inv inv inv inv
338 };
339
340 static filter_result filter_func(BMessage *msg, BHandler **target, BMessageFilter *filter)
341 {
342 switch (msg->what) {
343 case B_KEY_DOWN:
344 case B_KEY_UP: {
345 uint32 be_code = msg->FindInt32("key") & 0xff;
346 uint32 mac_code = keycode2mac[be_code];
347
348 // Intercept Ctrl-F1 (mount floppy disk shortcut)
349 uint32 mods = msg->FindInt32("modifiers");
350 if (be_code == 0x02 && (mods & B_CONTROL_KEY))
351 SysMountVolume("/dev/disk/floppy/raw");
352
353 if (mac_code == 0xff)
354 return B_DISPATCH_MESSAGE;
355 if (msg->what == B_KEY_DOWN)
356 ADBKeyDown(mac_code);
357 else
358 ADBKeyUp(mac_code);
359 return B_SKIP_MESSAGE;
360 }
361
362 case B_MODIFIERS_CHANGED: {
363 uint32 mods = msg->FindInt32("modifiers");
364 uint32 old_mods = msg->FindInt32("be:old_modifiers");
365 uint32 changed = mods ^ old_mods;
366 uint32 mask = 1;
367 for (int i=0; i<32; i++, mask<<=1)
368 if (changed & mask) {
369 uint32 mac_code = modifier2mac[i];
370 if (mac_code == 0xff)
371 continue;
372 if (mods & mask)
373 ADBKeyDown(mac_code);
374 else
375 ADBKeyUp(mac_code);
376 }
377 return B_SKIP_MESSAGE;
378 }
379
380 case B_MOUSE_MOVED: {
381 BPoint point;
382 msg->FindPoint("where", &point);
383 ADBMouseMoved(int(point.x), int(point.y));
384 return B_DISPATCH_MESSAGE; // Otherwise BitmapView::MouseMoved() wouldn't be called
385 }
386
387 case B_MOUSE_DOWN: {
388 uint32 buttons = msg->FindInt32("buttons");
389 if (buttons & B_PRIMARY_MOUSE_BUTTON)
390 ADBMouseDown(0);
391 if (buttons & B_SECONDARY_MOUSE_BUTTON)
392 ADBMouseDown(1);
393 if (buttons & B_TERTIARY_MOUSE_BUTTON)
394 ADBMouseDown(2);
395 return B_SKIP_MESSAGE;
396 }
397
398 case B_MOUSE_UP: // B_MOUSE_UP means "all buttons released"
399 ADBMouseUp(0);
400 ADBMouseUp(1);
401 ADBMouseUp(2);
402 return B_SKIP_MESSAGE;
403
404 default:
405 return B_DISPATCH_MESSAGE;
406 }
407 }
408
409
410 /*
411 * Window constructor
412 */
413
414 MacWindow::MacWindow(BRect frame) : BDirectWindow(frame, GetString(STR_WINDOW_TITLE), B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_CLOSABLE | B_NOT_ZOOMABLE)
415 {
416 supports_direct_mode = SupportsWindowMode();
417
418 // Move window to right position
419 Lock();
420 MoveTo(80, 60);
421
422 // Allocate bitmap and Mac frame buffer
423 uint32 x = frame.IntegerWidth() + 1;
424 uint32 y = frame.IntegerHeight() + 1;
425 the_bitmap = new BBitmap(frame, B_COLOR_8_BIT);
426 the_buffer = new uint8[x * (y + 2)]; // "y + 2" for safety
427
428 // Set VideoMonitor
429 #if REAL_ADDRESSING
430 VideoMonitor.mac_frame_base = (uint32)the_buffer;
431 #else
432 VideoMonitor.mac_frame_base = MacFrameBaseMac;
433 #endif
434 VideoMonitor.bytes_per_row = x;
435 VideoMonitor.x = x;
436 VideoMonitor.y = y;
437 VideoMonitor.mode = VMODE_8BIT;
438
439 #if !REAL_ADDRESSING
440 // Set variables for UAE memory mapping
441 MacFrameBaseHost = the_buffer;
442 MacFrameSize = VideoMonitor.bytes_per_row * VideoMonitor.y;
443 MacFrameLayout = FLAYOUT_DIRECT;
444 #endif
445
446 // Create bitmap view
447 main_view = new BitmapView(frame, the_bitmap);
448 AddChild(main_view);
449 main_view->MakeFocus();
450
451 // Read frame skip prefs
452 frame_skip = PrefsFindInt32("frameskip");
453 if (frame_skip == 0)
454 frame_skip = 1;
455
456 // Set up menus
457 BRect bounds = Bounds();
458 bounds.OffsetBy(0, bounds.IntegerHeight() + 1);
459 BMenuItem *item;
460 BMenuBar *bar = new BMenuBar(bounds, "menu");
461 BMenu *menu = new BMenu(GetString(STR_WINDOW_MENU));
462 menu->AddItem(new BMenuItem(GetString(STR_WINDOW_ITEM_ABOUT), new BMessage(MSG_ABOUT_REQUESTED)));
463 menu->AddItem(new BSeparatorItem);
464 BMenu *submenu = new BMenu(GetString(STR_WINDOW_ITEM_REFRESH));
465 submenu->AddItem(new BMenuItem(GetString(STR_REF_5HZ_LAB), new BMessage(MSG_REF_5HZ)));
466 submenu->AddItem(new BMenuItem(GetString(STR_REF_7_5HZ_LAB), new BMessage(MSG_REF_7_5HZ)));
467 submenu->AddItem(new BMenuItem(GetString(STR_REF_10HZ_LAB), new BMessage(MSG_REF_10HZ)));
468 submenu->AddItem(new BMenuItem(GetString(STR_REF_15HZ_LAB), new BMessage(MSG_REF_15HZ)));
469 submenu->AddItem(new BMenuItem(GetString(STR_REF_30HZ_LAB), new BMessage(MSG_REF_30HZ)));
470 submenu->AddItem(new BMenuItem(GetString(STR_REF_60HZ_LAB), new BMessage(MSG_REF_60HZ)));
471 submenu->SetRadioMode(true);
472 if (frame_skip == 12) {
473 if ((item = submenu->FindItem(GetString(STR_REF_5HZ_LAB))) != NULL)
474 item->SetMarked(true);
475 } else if (frame_skip == 8) {
476 if ((item = submenu->FindItem(GetString(STR_REF_7_5HZ_LAB))) != NULL)
477 item->SetMarked(true);
478 } else if (frame_skip == 6) {
479 if ((item = submenu->FindItem(GetString(STR_REF_10HZ_LAB))) != NULL)
480 item->SetMarked(true);
481 } else if (frame_skip == 4) {
482 if ((item = submenu->FindItem(GetString(STR_REF_15HZ_LAB))) != NULL)
483 item->SetMarked(true);
484 } else if (frame_skip == 2) {
485 if ((item = submenu->FindItem(GetString(STR_REF_30HZ_LAB))) != NULL)
486 item->SetMarked(true);
487 } else if (frame_skip == 1) {
488 if ((item = submenu->FindItem(GetString(STR_REF_60HZ_LAB))) != NULL)
489 item->SetMarked(true);
490 }
491 menu->AddItem(submenu);
492 submenu = new BMenu(GetString(STR_WINDOW_ITEM_MOUNT));
493 SysCreateVolumeMenu(submenu, MSG_MOUNT);
494 menu->AddItem(submenu);
495 #if DEBUGGER_AVAILABLE
496 menu->AddItem(new BMenuItem("Debugger", new BMessage(MSG_DEBUGGER)));
497 #endif
498 bar->AddItem(menu);
499 AddChild(bar);
500 SetKeyMenuBar(bar);
501 int mbar_height = bar->Frame().IntegerHeight() + 1;
502
503 // Resize window to fit menu bar
504 ResizeBy(0, mbar_height);
505
506 // Set absolute mouse mode and get scroll lock state
507 ADBSetRelMouseMode(false);
508 mouse_in_view = true;
509 old_scroll_lock_state = modifiers() & B_SCROLL_LOCK;
510 if (old_scroll_lock_state)
511 SetTitle(GetString(STR_WINDOW_TITLE_FROZEN));
512 else
513 SetTitle(GetString(STR_WINDOW_TITLE));
514
515 // Keep window aligned to 8-byte frame buffer boundaries for faster blitting
516 SetWindowAlignment(B_BYTE_ALIGNMENT, 8);
517
518 // Create drawing semaphore (for direct mode)
519 drawing_sem = create_sem(0, "direct frame buffer access");
520
521 // Start 60Hz interrupt
522 tick_thread_active = true;
523 tick_thread = spawn_thread(tick_func, "Window Redraw", B_DISPLAY_PRIORITY, this);
524 resume_thread(tick_thread);
525
526 // Add filter for keyboard and mouse events
527 BMessageFilter *filter = new BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE, filter_func);
528 main_view->AddFilter(filter);
529
530 // Show window
531 Unlock();
532 Show();
533 Sync();
534 }
535
536
537 /*
538 * Window destructor
539 */
540
541 MacWindow::~MacWindow()
542 {
543 // Restore cursor
544 mouse_in_view = false;
545 be_app->SetCursor(B_HAND_CURSOR);
546
547 // Hide window
548 Hide();
549 Sync();
550
551 // Stop 60Hz interrupt
552 status_t l;
553 tick_thread_active = false;
554 delete_sem(drawing_sem);
555 wait_for_thread(tick_thread, &l);
556
557 // Free bitmap and frame buffer
558 delete the_bitmap;
559 delete[] the_buffer;
560
561 // Tell emulator that we're done
562 the_window = NULL;
563 }
564
565
566 /*
567 * Window connected/disconnected
568 */
569
570 void MacWindow::DirectConnected(direct_buffer_info *info)
571 {
572 switch (info->buffer_state & B_DIRECT_MODE_MASK) {
573 case B_DIRECT_STOP:
574 acquire_sem(drawing_sem);
575 break;
576 case B_DIRECT_MODIFY:
577 acquire_sem(drawing_sem);
578 case B_DIRECT_START:
579 bits = (void *)((uint8 *)info->bits + info->window_bounds.top * info->bytes_per_row + info->window_bounds.left * info->bits_per_pixel / 8);
580 bytes_per_row = info->bytes_per_row;
581 pixel_format = info->pixel_format;
582 unclipped = false;
583 if (info->clip_list_count == 1)
584 if (memcmp(&info->clip_bounds, &info->window_bounds, sizeof(clipping_rect)) == 0)
585 unclipped = true;
586 release_sem(drawing_sem);
587 break;
588 }
589 }
590
591
592 /*
593 * Handle redraw and menu messages
594 */
595
596 void MacWindow::MessageReceived(BMessage *msg)
597 {
598 BMessage *msg2;
599
600 switch (msg->what) {
601 case MSG_REDRAW: {
602
603 // Prevent backlog of messages
604 MessageQueue()->Lock();
605 while ((msg2 = MessageQueue()->FindMessage(MSG_REDRAW, 0)) != NULL) {
606 MessageQueue()->RemoveMessage(msg2);
607 delete msg2;
608 }
609 MessageQueue()->Unlock();
610
611 // Convert Mac screen buffer to BeOS palette and blit
612 uint8 *source = the_buffer - 1;
613 uint8 *dest = (uint8 *)the_bitmap->Bits() - 1;
614 uint32 length = VideoMonitor.bytes_per_row * VideoMonitor.y;
615 for (int i=0; i<length; i++)
616 *++dest = remap_mac_be[*++source];
617 BRect update_rect = BRect(0, 0, VideoMonitor.x-1, VideoMonitor.y-1);
618 main_view->DrawBitmapAsync(the_bitmap, update_rect, update_rect);
619 break;
620 }
621
622 case MSG_ABOUT_REQUESTED: {
623 char str[256];
624 sprintf(str, GetString(STR_ABOUT_TEXT1), VERSION_MAJOR, VERSION_MINOR);
625 strcat(str, " ");
626 strcat(str, GetString(STR_ABOUT_TEXT2));
627 BAlert *about = new BAlert(GetString(STR_WINDOW_TITLE), str, GetString(STR_OK_BUTTON));
628 about->Go();
629 break;
630 }
631
632 case MSG_REF_5HZ:
633 PrefsReplaceInt32("frameskip", frame_skip = 12);
634 break;
635
636 case MSG_REF_7_5HZ:
637 PrefsReplaceInt32("frameskip", frame_skip = 8);
638 break;
639
640 case MSG_REF_10HZ:
641 PrefsReplaceInt32("frameskip", frame_skip = 6);
642 break;
643
644 case MSG_REF_15HZ:
645 PrefsReplaceInt32("frameskip", frame_skip = 4);
646 break;
647
648 case MSG_REF_30HZ:
649 PrefsReplaceInt32("frameskip", frame_skip = 2);
650 break;
651
652 case MSG_REF_60HZ:
653 PrefsReplaceInt32("frameskip", frame_skip = 1);
654 break;
655
656 case MSG_MOUNT: {
657 BMenuItem *source = NULL;
658 msg->FindPointer("source", (void **)&source);
659 if (source)
660 SysMountVolume(source->Label());
661 break;
662 }
663
664 #if DEBUGGER_AVAILABLE
665 case MSG_DEBUGGER:
666 extern int debugging;
667 debugging = 1;
668 regs.spcflags |= SPCFLAG_BRK;
669 break;
670 #endif
671
672 default:
673 BDirectWindow::MessageReceived(msg);
674 }
675 }
676
677
678 /*
679 * Window activated/deactivated
680 */
681
682 void MacWindow::WindowActivated(bool active)
683 {
684 if (active) {
685 frame_skip = PrefsFindInt32("frameskip");
686 if (frame_skip == 0)
687 frame_skip = 1;
688 } else
689 frame_skip = 12; // 5Hz in background
690 }
691
692
693 /*
694 * 60Hz interrupt routine
695 */
696
697 status_t MacWindow::tick_func(void *arg)
698 {
699 MacWindow *obj = (MacWindow *)arg;
700 static int tick_counter = 0;
701 while (obj->tick_thread_active) {
702
703 tick_counter++;
704 if (tick_counter >= obj->frame_skip) {
705 tick_counter = 0;
706
707 // Window title is determined by Scroll Lock state
708 uint32 scroll_lock_state = modifiers() & B_SCROLL_LOCK;
709 if (scroll_lock_state != obj->old_scroll_lock_state) {
710 if (scroll_lock_state)
711 obj->SetTitle(GetString(STR_WINDOW_TITLE_FROZEN));
712 else
713 obj->SetTitle(GetString(STR_WINDOW_TITLE));
714 obj->old_scroll_lock_state = scroll_lock_state;
715 }
716
717 // Has the Mac started?
718 if (HasMacStarted()) {
719
720 // Yes, set new cursor image if it was changed
721 if (memcmp(MacCursor+4, Mac2HostAddr(0x844), 64)) {
722 Mac2Host_memcpy(MacCursor+4, 0x844, 64); // Cursor image
723 MacCursor[2] = ReadMacInt8(0x885); // Hotspot
724 MacCursor[3] = ReadMacInt8(0x887);
725 be_app->SetCursor(MacCursor);
726 }
727 }
728
729 // Refresh screen unless Scroll Lock is down
730 if (!scroll_lock_state) {
731
732 // If direct frame buffer access is supported and the content area is completely visible,
733 // convert the Mac screen buffer directly. Otherwise, send a message to the window to do
734 // it into a bitmap
735 if (obj->supports_direct_mode) {
736 if (acquire_sem(obj->drawing_sem) != B_NO_ERROR)
737 return 0;
738 if (obj->unclipped && obj->pixel_format == B_CMAP8) {
739 uint8 *source = obj->the_buffer - 1;
740 uint8 *dest = (uint8 *)obj->bits;
741 uint32 bytes_per_row = obj->bytes_per_row;
742 int xsize = VideoMonitor.x;
743 int ysize = VideoMonitor.y;
744 for (int y=0; y<ysize; y++) {
745 uint32 *p = (uint32 *)dest - 1;
746 for (int x=0; x<xsize/4; x++) {
747 #if B_HOST_IS_BENDIAN
748 uint32 c = obj->remap_mac_be[*++source] << 24;
749 c |= obj->remap_mac_be[*++source] << 16;
750 c |= obj->remap_mac_be[*++source] << 8;
751 c |= obj->remap_mac_be[*++source];
752 #else
753 uint32 c = obj->remap_mac_be[*++source];
754 c |= obj->remap_mac_be[*++source] << 8;
755 c |= obj->remap_mac_be[*++source] << 16;
756 c |= obj->remap_mac_be[*++source] << 24;
757 #endif
758 *++p = c;
759 }
760 dest += bytes_per_row;
761 }
762 } else
763 obj->PostMessage(MSG_REDRAW);
764 release_sem(obj->drawing_sem);
765 } else
766 obj->PostMessage(MSG_REDRAW);
767 }
768 }
769 snooze(16666);
770 }
771 return 0;
772 }
773
774
775 /*
776 * Mouse moved in window
777 */
778
779 void BitmapView::MouseMoved(BPoint point, uint32 transit, const BMessage *message)
780 {
781 switch (transit) {
782 case B_ENTERED_VIEW:
783 ((MacWindow *)Window())->mouse_in_view = true;
784 be_app->SetCursor(MacCursor);
785 break;
786 case B_EXITED_VIEW:
787 ((MacWindow *)Window())->mouse_in_view = false;
788 be_app->SetCursor(B_HAND_CURSOR);
789 break;
790 }
791 }
792
793
794 /*
795 * Screen constructor
796 */
797
798 MacScreen::MacScreen(const char *name, int mode_bit, status_t *error) : BWindowScreen(name, 1 << mode_bit, error), tick_thread(-1)
799 {
800 // Set all variables
801 frame_backup = NULL;
802 palette_changed = false;
803 screen_active = false;
804 quitting = false;
805
806 // Set relative mouse mode
807 ADBSetRelMouseMode(true);
808
809 // Create view to get mouse events
810 main_view = new BView(Frame(), NULL, B_FOLLOW_NONE, 0);
811 AddChild(main_view);
812
813 // Start 60Hz interrupt
814 tick_thread_active = true;
815 tick_thread = spawn_thread(tick_func, "Polling sucks...", B_DISPLAY_PRIORITY, this);
816 resume_thread(tick_thread);
817
818 // Add filter for keyboard and mouse events
819 BMessageFilter *filter = new BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE, filter_func);
820 AddCommonFilter(filter);
821 }
822
823
824 /*
825 * Screen destructor
826 */
827
828 MacScreen::~MacScreen()
829 {
830 // Stop 60Hz interrupt
831 if (tick_thread > 0) {
832 status_t l;
833 tick_thread_active = false;
834 wait_for_thread(tick_thread, &l);
835 }
836
837 // Tell emulator that we're done
838 the_screen = NULL;
839 }
840
841
842 /*
843 * Screen closed
844 */
845
846 void MacScreen::Quit(void)
847 {
848 // Tell ScreenConnected() that we are quitting
849 quitting = true;
850 BWindowScreen::Quit();
851 }
852
853
854 /*
855 * Screen connected/disconnected
856 */
857
858 void MacScreen::ScreenConnected(bool active)
859 {
860 graphics_card_info *info = CardInfo();
861 screen_active = active;
862
863 if (active == true) {
864
865 // Set VideoMonitor
866 #if REAL_ADDRESSING
867 VideoMonitor.mac_frame_base = (uint32)info->frame_buffer;
868 #else
869 VideoMonitor.mac_frame_base = MacFrameBaseMac;
870 #endif
871 VideoMonitor.bytes_per_row = info->bytes_per_row;
872 VideoMonitor.x = info->width;
873 VideoMonitor.y = info->height;
874 switch (info->bits_per_pixel) {
875 case 8:
876 VideoMonitor.mode = VMODE_8BIT;
877 break;
878 case 15:
879 case 16:
880 VideoMonitor.mode = VMODE_16BIT;
881 break;
882 case 32:
883 VideoMonitor.mode = VMODE_32BIT;
884 break;
885 default:
886 VideoMonitor.mode = VMODE_8BIT;
887 break;
888 }
889
890 #if !REAL_ADDRESSING
891 // Set variables for UAE memory mapping
892 MacFrameBaseHost = (uint8 *)info->frame_buffer;
893 MacFrameSize = VideoMonitor.bytes_per_row * VideoMonitor.y;
894 switch (info->bits_per_pixel) {
895 case 15:
896 MacFrameLayout = FLAYOUT_HOST_555;
897 break;
898 case 16:
899 MacFrameLayout = FLAYOUT_HOST_565;
900 break;
901 case 32:
902 MacFrameLayout = FLAYOUT_HOST_888;
903 break;
904 default:
905 MacFrameLayout = FLAYOUT_DIRECT;
906 break;
907 }
908 #endif
909
910 // Copy from backup store to frame buffer
911 if (frame_backup != NULL) {
912 memcpy(info->frame_buffer, frame_backup, VideoMonitor.bytes_per_row * VideoMonitor.y);
913 delete[] frame_backup;
914 frame_backup = NULL;
915 }
916
917 // Restore palette
918 if (VideoMonitor.mode == VMODE_8BIT)
919 SetColorList(palette);
920
921 // Restart/signal emulator thread
922 release_sem(mac_os_lock);
923
924 } else {
925
926 if (!quitting) {
927
928 // Stop emulator thread
929 acquire_sem(mac_os_lock);
930
931 // Create backup store and save frame buffer
932 frame_backup = new uint8[VideoMonitor.bytes_per_row * VideoMonitor.y];
933 memcpy(frame_backup, info->frame_buffer, VideoMonitor.bytes_per_row * VideoMonitor.y);
934 }
935 }
936 }
937
938
939 /*
940 * Screen 60Hz interrupt routine
941 */
942
943 status_t MacScreen::tick_func(void *arg)
944 {
945 MacScreen *obj = (MacScreen *)arg;
946 while (obj->tick_thread_active) {
947
948 // Wait
949 snooze(16667);
950
951 // Workspace activated? Then poll the mouse and set the palette if needed
952 if (!obj->quitting && obj->LockWithTimeout(200000) == B_OK) {
953 if (obj->screen_active) {
954 BPoint pt;
955 uint32 button = 0;
956 if (obj->palette_changed) {
957 obj->palette_changed = false;
958 obj->SetColorList(obj->palette);
959 }
960 obj->main_view->GetMouse(&pt, &button);
961 set_mouse_position(320, 240);
962 ADBMouseMoved(int(pt.x) - 320, int(pt.y) - 240);
963 if (button & B_PRIMARY_MOUSE_BUTTON)
964 ADBMouseDown(0);
965 if (!(button & B_PRIMARY_MOUSE_BUTTON))
966 ADBMouseUp(0);
967 if (button & B_SECONDARY_MOUSE_BUTTON)
968 ADBMouseDown(1);
969 if (!(button & B_SECONDARY_MOUSE_BUTTON))
970 ADBMouseUp(1);
971 if (button & B_TERTIARY_MOUSE_BUTTON)
972 ADBMouseDown(2);
973 if (!(button & B_TERTIARY_MOUSE_BUTTON))
974 ADBMouseUp(2);
975 }
976 obj->Unlock();
977 }
978 }
979 return 0;
980 }