ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/BeOS/video_window.h
Revision: 1.2
Committed: 2004-01-12T15:37:19Z (20 years, 10 months ago) by cebix
Content type: text/plain
Branch: MAIN
Changes since 1.1: +1 -1 lines
Log Message:
Happy New Year! :)

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * video_window.h - Window video modes
3     *
4 cebix 1.2 * SheepShaver (C) 1997-2004 Marc Hellwig and Christian Bauer
5 cebix 1.1 *
6     * This program is free software; you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation; either version 2 of the License, or
9     * (at your option) any later version.
10     *
11     * This program is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with this program; if not, write to the Free Software
18     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19     */
20    
21     #include <DirectWindow.h>
22    
23    
24     // Messages
25     static const uint32 MSG_REDRAW = 'draw';
26     static const uint32 MSG_ABOUT_REQUESTED = B_ABOUT_REQUESTED;
27     static const uint32 MSG_REF_5HZ = ' 5Hz';
28     static const uint32 MSG_REF_7_5HZ = ' 7Hz';
29     static const uint32 MSG_REF_10HZ = '10Hz';
30     static const uint32 MSG_REF_15HZ = '15Hz';
31     static const uint32 MSG_REF_30HZ = '30Hz';
32     static const uint32 MSG_REF_60HZ = '60Hz';
33     static const uint32 MSG_MOUNT = 'moun';
34    
35     static bool mouse_in_view; // Flag: Mouse pointer within bitmap view
36    
37     // From sys_beos.cpp
38     extern void SysCreateVolumeMenu(BMenu *menu, uint32 msg);
39     extern void SysMountVolume(const char *name);
40    
41    
42     /*
43     * A simple view class for blitting a bitmap on the screen
44     */
45    
46     class BitmapView : public BView {
47     public:
48     BitmapView(BRect frame, BBitmap *bitmap) : BView(frame, "bitmap", B_FOLLOW_NONE, B_WILL_DRAW)
49     {
50     the_bitmap = bitmap;
51     }
52     virtual void Draw(BRect update)
53     {
54     if (the_bitmap)
55     DrawBitmap(the_bitmap, update, update);
56     }
57     virtual void MouseMoved(BPoint point, uint32 transit, const BMessage *message);
58    
59     private:
60     BBitmap *the_bitmap;
61     };
62    
63    
64     /*
65     * Window class
66     */
67    
68     class MacWindow : public BDirectWindow {
69     public:
70     MacWindow(BRect frame);
71     virtual ~MacWindow();
72     virtual void MessageReceived(BMessage *msg);
73     virtual void DirectConnected(direct_buffer_info *info);
74     virtual void WindowActivated(bool active);
75    
76     int32 frame_skip;
77     bool cursor_changed; // Flag: set new cursor image in tick function
78    
79     private:
80     static status_t tick_func(void *arg);
81    
82     BitmapView *main_view;
83     BBitmap *the_bitmap;
84     uint8 *the_buffer;
85    
86     uint32 old_scroll_lock_state;
87    
88     thread_id tick_thread;
89     bool tick_thread_active;
90    
91     bool supports_direct_mode;
92     bool bit_bang;
93     sem_id drawing_sem;
94    
95     color_space mode;
96     void *bits;
97     int32 bytes_per_row;
98     color_space pixel_format;
99     bool unclipped;
100     };
101    
102    
103     // Pointer to our window
104     static MacWindow *the_window = NULL;
105    
106    
107     /*
108     * Window constructor
109     */
110    
111     MacWindow::MacWindow(BRect frame) : BDirectWindow(frame, GetString(STR_WINDOW_TITLE), B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_CLOSABLE | B_NOT_ZOOMABLE)
112     {
113     D(bug("Window constructor\n"));
114     supports_direct_mode = SupportsWindowMode();
115     cursor_changed = false;
116     bit_bang = supports_direct_mode && PrefsFindBool("bitbang");
117    
118     // Move window to right position
119     Lock();
120     MoveTo(80, 60);
121    
122     // Allocate bitmap
123     {
124     BScreen scr(this);
125     mode = B_COLOR_8_BIT;
126     switch (VModes[cur_mode].viAppleMode) {
127     case APPLE_8_BIT:
128     mode = B_COLOR_8_BIT;
129     bit_bang = false;
130     break;
131     case APPLE_16_BIT:
132     mode = B_RGB_16_BIT;
133     if (scr.ColorSpace() != B_RGB15_BIG && scr.ColorSpace() != B_RGBA15_BIG)
134     bit_bang = false;
135     break;
136     case APPLE_32_BIT:
137     mode = B_RGB_32_BIT;
138     if (scr.ColorSpace() != B_RGB32_BIG && scr.ColorSpace() != B_RGBA32_BIG)
139     bit_bang = false;
140     break;
141     }
142     }
143     if (bit_bang) {
144     the_bitmap = NULL;
145     the_buffer = NULL;
146     } else {
147     the_bitmap = new BBitmap(frame, mode);
148     the_buffer = new uint8[VModes[cur_mode].viRowBytes * (VModes[cur_mode].viYsize + 2)]; // ("height + 2" for safety)
149     screen_base = (uint32)the_buffer;
150     }
151    
152     // Create bitmap view
153     main_view = new BitmapView(frame, the_bitmap);
154     AddChild(main_view);
155     main_view->MakeFocus();
156    
157     // Read frame skip prefs
158     frame_skip = PrefsFindInt32("frameskip");
159    
160     // Set up menus
161     BRect bounds = Bounds();
162     bounds.OffsetBy(0, bounds.IntegerHeight() + 1);
163     BMenuItem *item;
164     BMenuBar *bar = new BMenuBar(bounds, "menu");
165     BMenu *menu = new BMenu(GetString(STR_WINDOW_MENU));
166     menu->AddItem(new BMenuItem(GetString(STR_WINDOW_ITEM_ABOUT), new BMessage(MSG_ABOUT_REQUESTED)));
167     menu->AddItem(new BSeparatorItem);
168     BMenu *submenu = new BMenu(GetString(STR_WINDOW_ITEM_REFRESH));
169     submenu->AddItem(new BMenuItem(GetString(STR_REF_5HZ_LAB), new BMessage(MSG_REF_5HZ)));
170     submenu->AddItem(new BMenuItem(GetString(STR_REF_7_5HZ_LAB), new BMessage(MSG_REF_7_5HZ)));
171     submenu->AddItem(new BMenuItem(GetString(STR_REF_10HZ_LAB), new BMessage(MSG_REF_10HZ)));
172     submenu->AddItem(new BMenuItem(GetString(STR_REF_15HZ_LAB), new BMessage(MSG_REF_15HZ)));
173     submenu->AddItem(new BMenuItem(GetString(STR_REF_30HZ_LAB), new BMessage(MSG_REF_30HZ)));
174     submenu->AddItem(new BMenuItem(GetString(STR_REF_60HZ_LAB), new BMessage(MSG_REF_60HZ)));
175     submenu->SetRadioMode(true);
176     if (frame_skip == 12) {
177     if ((item = submenu->FindItem(GetString(STR_REF_5HZ_LAB))) != NULL)
178     item->SetMarked(true);
179     } else if (frame_skip == 8) {
180     if ((item = submenu->FindItem(GetString(STR_REF_7_5HZ_LAB))) != NULL)
181     item->SetMarked(true);
182     } else if (frame_skip == 6) {
183     if ((item = submenu->FindItem(GetString(STR_REF_10HZ_LAB))) != NULL)
184     item->SetMarked(true);
185     } else if (frame_skip == 4) {
186     if ((item = submenu->FindItem(GetString(STR_REF_15HZ_LAB))) != NULL)
187     item->SetMarked(true);
188     } else if (frame_skip == 2) {
189     if ((item = submenu->FindItem(GetString(STR_REF_30HZ_LAB))) != NULL)
190     item->SetMarked(true);
191     } else if (frame_skip == 1) {
192     if ((item = submenu->FindItem(GetString(STR_REF_60HZ_LAB))) != NULL)
193     item->SetMarked(true);
194     }
195     menu->AddItem(submenu);
196     submenu = new BMenu(GetString(STR_WINDOW_ITEM_MOUNT));
197     SysCreateVolumeMenu(submenu, MSG_MOUNT);
198     menu->AddItem(submenu);
199     bar->AddItem(menu);
200     AddChild(bar);
201     SetKeyMenuBar(bar);
202     int mbar_height = bar->Frame().IntegerHeight() + 1;
203    
204     // Resize window to fit menu bar
205     ResizeBy(0, mbar_height);
206    
207     // Set mouse mode and scroll lock state
208     ADBSetRelMouseMode(false);
209     mouse_in_view = true;
210     old_scroll_lock_state = modifiers() & B_SCROLL_LOCK;
211     if (old_scroll_lock_state)
212     SetTitle(GetString(STR_WINDOW_TITLE_FROZEN));
213     else
214     SetTitle(GetString(STR_WINDOW_TITLE));
215    
216     // Clear Mac cursor image
217     memset(MacCursor + 4, 0, 64);
218    
219     // Keep window aligned to 8-byte frame buffer boundaries for faster blitting
220     SetWindowAlignment(B_BYTE_ALIGNMENT, 8);
221    
222     // Create drawing semaphore (for direct mode)
223     drawing_sem = create_sem(0, "direct frame buffer access");
224    
225     // Start 60Hz interrupt
226     tick_thread_active = true;
227     tick_thread = spawn_thread(tick_func, "Window Redraw", B_DISPLAY_PRIORITY, this);
228     resume_thread(tick_thread);
229    
230     // Add filter for keyboard and mouse events
231     BMessageFilter *filter = new BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE, filter_func);
232     main_view->AddFilter(filter);
233    
234     // Show window
235     Unlock();
236     Show();
237     Sync();
238     D(bug("Window constructor done\n"));
239     }
240    
241    
242     /*
243     * Window destructor
244     */
245    
246     MacWindow::~MacWindow()
247     {
248     // Restore cursor
249     mouse_in_view = false;
250     be_app->SetCursor(B_HAND_CURSOR);
251    
252     // Hide window
253     D(bug("Window destructor, hiding window\n"));
254     Hide();
255     Sync();
256    
257     // Stop 60Hz interrupt
258     D(bug("Quitting tick thread\n"));
259     status_t l;
260     tick_thread_active = false;
261     delete_sem(drawing_sem);
262     while (wait_for_thread(tick_thread, &l) == B_INTERRUPTED) ;
263     D(bug("tick thread quit\n"));
264    
265     // dispose allocated memory
266     delete the_bitmap;
267     delete[] the_buffer;
268    
269     // Tell emulator that we're done
270     the_window = NULL;
271     D(bug("Window destructor done\n"));
272     }
273    
274    
275     /*
276     * Window connected/disconnected
277     */
278    
279     void MacWindow::DirectConnected(direct_buffer_info *info)
280     {
281     D(bug("DirectConnected, state %d\n", info->buffer_state));
282     switch (info->buffer_state & B_DIRECT_MODE_MASK) {
283     case B_DIRECT_STOP:
284     acquire_sem(drawing_sem);
285     break;
286     case B_DIRECT_MODIFY:
287     acquire_sem(drawing_sem);
288     case B_DIRECT_START:
289     bits = (void *)((uint8 *)info->bits + info->window_bounds.top * info->bytes_per_row + info->window_bounds.left * info->bits_per_pixel / 8);
290     bytes_per_row = info->bytes_per_row;
291     pixel_format = info->pixel_format;
292     unclipped = false;
293     if (info->clip_list_count == 1)
294     if (memcmp(&info->clip_bounds, &info->window_bounds, sizeof(clipping_rect)) == 0)
295     unclipped = true;
296     if (bit_bang) {
297     screen_base = (uint32)bits;
298     VModes[cur_mode].viRowBytes = bytes_per_row;
299     }
300     release_sem(drawing_sem);
301     break;
302     }
303     D(bug("DirectConnected done\n"));
304     }
305    
306    
307     /*
308     * Handles redraw messages
309     */
310    
311     void MacWindow::MessageReceived(BMessage *msg)
312     {
313     BMessage *msg2;
314    
315     switch (msg->what) {
316     case MSG_REDRAW: {
317    
318     // Prevent backlog of messages
319     MessageQueue()->Lock();
320     while ((msg2 = MessageQueue()->FindMessage(MSG_REDRAW, 0)) != NULL) {
321     MessageQueue()->RemoveMessage(msg2);
322     delete msg2;
323     }
324     MessageQueue()->Unlock();
325    
326     // Convert Mac screen buffer to BeOS palette and blit
327     uint32 length = VModes[cur_mode].viRowBytes * VModes[cur_mode].viYsize;
328     if (mode == B_COLOR_8_BIT) {
329     // Palette conversion
330     uint8 *source = the_buffer - 1;
331     uint8 *dest = (uint8 *)the_bitmap->Bits() - 1;
332     for (int i=0; i<length; i++)
333     *++dest = remap_mac_be[*++source];
334     } else if (mode == B_RGB_16_BIT) {
335     // Endianess conversion
336     uint16 *source = (uint16 *)the_buffer;
337     uint16 *dest = (uint16 *)the_bitmap->Bits() - 1;
338     for (int i=0; i<length/2; i++)
339     *++dest = __lhbrx(source++, 0);
340     } else if (mode == B_RGB_32_BIT) {
341     // Endianess conversion
342     uint32 *source = (uint32 *)the_buffer;
343     uint32 *dest = (uint32 *)the_bitmap->Bits() - 1;
344     for (int i=0; i<length/4; i++)
345     *++dest = __lwbrx(source++, 0);
346     }
347     BRect update_rect = BRect(0, 0, VModes[cur_mode].viXsize-1, VModes[cur_mode].viYsize-1);
348     main_view->DrawBitmapAsync(the_bitmap, update_rect, update_rect);
349     break;
350     }
351    
352     case MSG_ABOUT_REQUESTED:
353     OpenAboutWindow();
354     break;
355    
356     case MSG_REF_5HZ:
357     PrefsReplaceInt32("frameskip", frame_skip = 12);
358     break;
359    
360     case MSG_REF_7_5HZ:
361     PrefsReplaceInt32("frameskip", frame_skip = 8);
362     break;
363    
364     case MSG_REF_10HZ:
365     PrefsReplaceInt32("frameskip", frame_skip = 6);
366     break;
367    
368     case MSG_REF_15HZ:
369     PrefsReplaceInt32("frameskip", frame_skip = 4);
370     break;
371    
372     case MSG_REF_30HZ:
373     PrefsReplaceInt32("frameskip", frame_skip = 2);
374     break;
375    
376     case MSG_REF_60HZ:
377     PrefsReplaceInt32("frameskip", frame_skip = 1);
378     break;
379    
380     case MSG_MOUNT: {
381     BMenuItem *source = NULL;
382     msg->FindPointer("source", (void **)&source);
383     if (source)
384     SysMountVolume(source->Label());
385     break;
386     }
387    
388     default:
389     BDirectWindow::MessageReceived(msg);
390     }
391     }
392    
393    
394     /*
395     * Window activated/deactivated
396     */
397    
398     void MacWindow::WindowActivated(bool active)
399     {
400     video_activated = active;
401     if (active)
402     frame_skip = PrefsFindInt32("frameskip");
403     else
404     frame_skip = 12; // 5Hz in background
405     BDirectWindow::WindowActivated(active);
406     }
407    
408    
409     /*
410     * 60Hz interrupt routine
411     */
412    
413     status_t MacWindow::tick_func(void *arg)
414     {
415     MacWindow *obj = (MacWindow *)arg;
416     static int tick_counter = 0;
417     while (obj->tick_thread_active) {
418    
419     // Wait
420     snooze(16667);
421    
422     // Refresh window
423     if (!obj->bit_bang)
424     tick_counter++;
425     if (tick_counter >= obj->frame_skip) {
426     tick_counter = 0;
427    
428     // Window title is determined by Scroll Lock state
429     uint32 scroll_lock_state = modifiers() & B_SCROLL_LOCK;
430     if (scroll_lock_state != obj->old_scroll_lock_state) {
431     if (scroll_lock_state)
432     obj->SetTitle(GetString(STR_WINDOW_TITLE_FROZEN));
433     else
434     obj->SetTitle(GetString(STR_WINDOW_TITLE));
435     obj->old_scroll_lock_state = scroll_lock_state;
436     }
437    
438     // Refresh display unless Scroll Lock is down
439     if (!scroll_lock_state) {
440    
441     // If direct frame buffer access is supported and the content area is completely visible,
442     // convert the Mac screen buffer directly. Otherwise, send a message to the window to do
443     // it into a bitmap
444     if (obj->supports_direct_mode) {
445     if (acquire_sem_etc(obj->drawing_sem, 1, B_TIMEOUT, 200000) == B_NO_ERROR) {
446     if (obj->unclipped && obj->mode == B_COLOR_8_BIT && obj->pixel_format == B_CMAP8) {
447     uint8 *source = obj->the_buffer - 1;
448     uint8 *dest = (uint8 *)obj->bits;
449     uint32 bytes_per_row = obj->bytes_per_row;
450     int xsize = VModes[cur_mode].viXsize;
451     int ysize = VModes[cur_mode].viYsize;
452     for (int y=0; y<ysize; y++) {
453     uint32 *p = (uint32 *)dest - 1;
454     for (int x=0; x<xsize/4; x++) {
455     uint32 c = remap_mac_be[*++source] << 24;
456     c |= remap_mac_be[*++source] << 16;
457     c |= remap_mac_be[*++source] << 8;
458     c |= remap_mac_be[*++source];
459     *++p = c;
460     }
461     dest += bytes_per_row;
462     }
463     } else if (obj->unclipped && obj->mode == B_RGB_16_BIT && (obj->pixel_format == B_RGB15_BIG || obj->pixel_format == B_RGBA15_BIG)) {
464     uint8 *source = obj->the_buffer;
465     uint8 *dest = (uint8 *)obj->bits;
466     uint32 sbpr = VModes[cur_mode].viRowBytes;
467     uint32 dbpr = obj->bytes_per_row;
468     int xsize = VModes[cur_mode].viXsize;
469     int ysize = VModes[cur_mode].viYsize;
470     for (int y=0; y<ysize; y++) {
471     memcpy(dest, source, xsize * 2);
472     source += sbpr;
473     dest += dbpr;
474     }
475     } else if (obj->unclipped && obj->mode == B_RGB_32_BIT && (obj->pixel_format == B_RGB32_BIG || obj->pixel_format == B_RGBA32_BIG)) {
476     uint8 *source = obj->the_buffer;
477     uint8 *dest = (uint8 *)obj->bits;
478     uint32 sbpr = VModes[cur_mode].viRowBytes;
479     uint32 dbpr = obj->bytes_per_row;
480     int xsize = VModes[cur_mode].viXsize;
481     int ysize = VModes[cur_mode].viYsize;
482     for (int y=0; y<ysize; y++) {
483     memcpy(dest, source, xsize * 4);
484     source += sbpr;
485     dest += dbpr;
486     }
487     } else
488     obj->PostMessage(MSG_REDRAW);
489     release_sem(obj->drawing_sem);
490     }
491     } else
492     obj->PostMessage(MSG_REDRAW);
493     }
494     }
495    
496     // Set new cursor image if desired
497     if (obj->cursor_changed) {
498     if (mouse_in_view)
499     be_app->SetCursor(MacCursor);
500     obj->cursor_changed = false;
501     }
502     }
503     return 0;
504     }
505    
506    
507     /*
508     * Mouse moved
509     */
510    
511     void BitmapView::MouseMoved(BPoint point, uint32 transit, const BMessage *message)
512     {
513     switch (transit) {
514     case B_ENTERED_VIEW:
515     mouse_in_view = true;
516     be_app->SetCursor(MacCursor);
517     break;
518     case B_EXITED_VIEW:
519     mouse_in_view = false;
520     be_app->SetCursor(B_HAND_CURSOR);
521     break;
522     }
523     }