ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/BeOS/video_window.h
Revision: 1.4
Committed: 2008-01-01T09:47:38Z (16 years, 11 months ago) by gbeauche
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.3: +1 -1 lines
Log Message:
Happy New Year!

File Contents

# Content
1 /*
2 * video_window.h - Window video modes
3 *
4 * SheepShaver (C) 1997-2008 Marc Hellwig and Christian Bauer
5 *
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 }