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, 9 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

# User Rev Content
1 cebix 1.1 /*
2     * video_beos.cpp - Video/graphics emulation, BeOS specific stuff
3     *
4 cebix 1.5 * Basilisk II (C) 1997-2001 Christian Bauer
5 cebix 1.1 * 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 cebix 1.2 MacScreen(const char *name, int mode_bit, status_t *error);
141 cebix 1.1 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 cebix 1.3 Mac2Host_memcpy(MacCursor+4, 0x844, 64); // Cursor image
723     MacCursor[2] = ReadMacInt8(0x885); // Hotspot
724 cebix 1.1 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 cebix 1.2 MacScreen::MacScreen(const char *name, int mode_bit, status_t *error) : BWindowScreen(name, 1 << mode_bit, error), tick_thread(-1)
799 cebix 1.1 {
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     }