ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/SDL/video_sdl.cpp
Revision: 1.21
Committed: 2005-11-21T23:38:46Z (18 years, 7 months ago) by gbeauche
Branch: MAIN
Changes since 1.20: +26 -9 lines
Log Message:
Remove obsolete Cygwin/X11 addressing hack. Fix DirectX fullscreen mode
with hardware surface. On the other hand, DIB (SDL_VIDEODRIVER=windib)
always seems the fastest on my system for both windowed and fullscreen
modes.

File Contents

# Content
1 /*
2 * video_sdl.cpp - Video/graphics emulation, SDL specific stuff
3 *
4 * Basilisk II (C) 1997-2005 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 /*
22 * NOTES:
23 * The Ctrl key works like a qualifier for special actions:
24 * Ctrl-Tab = suspend DGA mode (TODO)
25 * Ctrl-Esc = emergency quit
26 * Ctrl-F1 = mount floppy
27 * Ctrl-F5 = grab mouse (in windowed mode)
28 *
29 * FIXMEs and TODOs:
30 * - Ctr-Tab for suspend/resume but how? SDL does not support that for non-Linux
31 * - Ctrl-Fn doesn't generate SDL_KEYDOWN events (SDL bug?)
32 * - Mouse acceleration, there is no API in SDL yet for that
33 * - Force relative mode in Grab mode even if SDL provides absolute coordinates?
34 * - Fullscreen mode
35 * - Gamma tables support is likely to be broken here
36 * - Events processing is bound to the general emulation thread as SDL requires
37 * to PumpEvents() within the same thread as the one that called SetVideoMode().
38 * Besides, there can't seem to be a way to call SetVideoMode() from a child thread.
39 * - Refresh performance is still slow. Use SDL_CreateRGBSurface()?
40 * - Backport hw cursor acceleration to Basilisk II?
41 * - Factor out code
42 */
43
44 #include "sysdeps.h"
45
46 #include <SDL.h>
47 #include <SDL_mutex.h>
48 #include <SDL_thread.h>
49 #include <errno.h>
50 #include <vector>
51
52 #include "cpu_emulation.h"
53 #include "main.h"
54 #include "adb.h"
55 #include "macos_util.h"
56 #include "prefs.h"
57 #include "user_strings.h"
58 #include "video.h"
59 #include "video_defs.h"
60 #include "video_blit.h"
61 #include "vm_alloc.h"
62
63 #define DEBUG 0
64 #include "debug.h"
65
66
67 // Supported video modes
68 using std::vector;
69 static vector<VIDEO_MODE> VideoModes;
70
71 // Display types
72 #ifdef SHEEPSHAVER
73 enum {
74 DISPLAY_WINDOW = DIS_WINDOW, // windowed display
75 DISPLAY_SCREEN = DIS_SCREEN // fullscreen display
76 };
77 extern int display_type; // See enum above
78 #else
79 enum {
80 DISPLAY_WINDOW, // windowed display
81 DISPLAY_SCREEN // fullscreen display
82 };
83 static int display_type = DISPLAY_WINDOW; // See enum above
84 #endif
85
86 // Constants
87 #ifdef WIN32
88 const char KEYCODE_FILE_NAME[] = "BasiliskII_keycodes";
89 #else
90 const char KEYCODE_FILE_NAME[] = DATADIR "/keycodes";
91 #endif
92
93
94 // Global variables
95 static int32 frame_skip; // Prefs items
96 static int16 mouse_wheel_mode;
97 static int16 mouse_wheel_lines;
98
99 static uint8 *the_buffer = NULL; // Mac frame buffer (where MacOS draws into)
100 static uint8 *the_buffer_copy = NULL; // Copy of Mac frame buffer (for refreshed modes)
101 static uint32 the_buffer_size; // Size of allocated the_buffer
102
103 static bool redraw_thread_active = false; // Flag: Redraw thread installed
104 #ifndef USE_CPU_EMUL_SERVICES
105 static volatile bool redraw_thread_cancel; // Flag: Cancel Redraw thread
106 static SDL_Thread *redraw_thread = NULL; // Redraw thread
107 #ifdef SHEEPSHAVER
108 static volatile bool thread_stop_req = false;
109 static volatile bool thread_stop_ack = false; // Acknowledge for thread_stop_req
110 #endif
111 #endif
112
113 #ifdef ENABLE_VOSF
114 static bool use_vosf = false; // Flag: VOSF enabled
115 #else
116 static const bool use_vosf = false; // VOSF not possible
117 #endif
118
119 static bool ctrl_down = false; // Flag: Ctrl key pressed
120 static bool caps_on = false; // Flag: Caps Lock on
121 static bool quit_full_screen = false; // Flag: DGA close requested from redraw thread
122 static bool emerg_quit = false; // Flag: Ctrl-Esc pressed, emergency quit requested from MacOS thread
123 static bool emul_suspended = false; // Flag: Emulator suspended
124
125 static bool classic_mode = false; // Flag: Classic Mac video mode
126
127 static bool use_keycodes = false; // Flag: Use keycodes rather than keysyms
128 static int keycode_table[256]; // X keycode -> Mac keycode translation table
129
130 // SDL variables
131 static int screen_depth; // Depth of current screen
132 static SDL_Cursor *sdl_cursor; // Copy of Mac cursor
133 static volatile bool cursor_changed = false; // Flag: cursor changed, redraw_func must update the cursor
134 static SDL_Color sdl_palette[256]; // Color palette to be used as CLUT and gamma table
135 static bool sdl_palette_changed = false; // Flag: Palette changed, redraw thread must set new colors
136 static const int sdl_eventmask = SDL_MOUSEBUTTONDOWNMASK | SDL_MOUSEBUTTONUPMASK | SDL_MOUSEMOTIONMASK | SDL_KEYUPMASK | SDL_KEYDOWNMASK | SDL_VIDEOEXPOSEMASK | SDL_QUITMASK;
137
138 // Mutex to protect palette
139 static SDL_mutex *sdl_palette_lock = NULL;
140 #define LOCK_PALETTE SDL_LockMutex(sdl_palette_lock)
141 #define UNLOCK_PALETTE SDL_UnlockMutex(sdl_palette_lock)
142
143 // Mutex to protect frame buffer
144 static SDL_mutex *frame_buffer_lock = NULL;
145 #define LOCK_FRAME_BUFFER SDL_LockMutex(frame_buffer_lock)
146 #define UNLOCK_FRAME_BUFFER SDL_UnlockMutex(frame_buffer_lock)
147
148 // Video refresh function
149 static void VideoRefreshInit(void);
150 static void (*video_refresh)(void);
151
152
153 // Prototypes
154 static int redraw_func(void *arg);
155
156 // From sys_unix.cpp
157 extern void SysMountFirstFloppy(void);
158
159
160 /*
161 * SDL surface locking glue
162 */
163
164 #ifdef ENABLE_VOSF
165 #define SDL_VIDEO_LOCK_VOSF_SURFACE(SURFACE) do { \
166 if ((SURFACE)->flags & (SDL_HWSURFACE | SDL_FULLSCREEN)) \
167 the_host_buffer = (uint8 *)(SURFACE)->pixels; \
168 } while (0)
169 #else
170 #define SDL_VIDEO_LOCK_VOSF_SURFACE(SURFACE)
171 #endif
172
173 #define SDL_VIDEO_LOCK_SURFACE(SURFACE) do { \
174 if (SDL_MUSTLOCK(SURFACE)) { \
175 SDL_LockSurface(SURFACE); \
176 SDL_VIDEO_LOCK_VOSF_SURFACE(SURFACE); \
177 } \
178 } while (0)
179
180 #define SDL_VIDEO_UNLOCK_SURFACE(SURFACE) do { \
181 if (SDL_MUSTLOCK(SURFACE)) \
182 SDL_UnlockSurface(SURFACE); \
183 } while (0)
184
185
186 /*
187 * Framebuffer allocation routines
188 */
189
190 static void *vm_acquire_framebuffer(uint32 size)
191 {
192 return vm_acquire(size);
193 }
194
195 static inline void vm_release_framebuffer(void *fb, uint32 size)
196 {
197 vm_release(fb, size);
198 }
199
200
201 /*
202 * SheepShaver glue
203 */
204
205 #ifdef SHEEPSHAVER
206 // Color depth modes type
207 typedef int video_depth;
208
209 // 1, 2, 4 and 8 bit depths use a color palette
210 static inline bool IsDirectMode(VIDEO_MODE const & mode)
211 {
212 return IsDirectMode(mode.viAppleMode);
213 }
214
215 // Abstract base class representing one (possibly virtual) monitor
216 // ("monitor" = rectangular display with a contiguous frame buffer)
217 class monitor_desc {
218 public:
219 monitor_desc(const vector<VIDEO_MODE> &available_modes, video_depth default_depth, uint32 default_id) {}
220 virtual ~monitor_desc() {}
221
222 // Get current Mac frame buffer base address
223 uint32 get_mac_frame_base(void) const {return screen_base;}
224
225 // Set Mac frame buffer base address (called from switch_to_mode())
226 void set_mac_frame_base(uint32 base) {screen_base = base;}
227
228 // Get current video mode
229 const VIDEO_MODE &get_current_mode(void) const {return VModes[cur_mode];}
230
231 // Called by the video driver to switch the video mode on this display
232 // (must call set_mac_frame_base())
233 virtual void switch_to_current_mode(void) = 0;
234
235 // Called by the video driver to set the color palette (in indexed modes)
236 // or the gamma table (in direct modes)
237 virtual void set_palette(uint8 *pal, int num) = 0;
238 };
239
240 // Vector of pointers to available monitor descriptions, filled by VideoInit()
241 static vector<monitor_desc *> VideoMonitors;
242
243 // Find Apple mode matching best specified dimensions
244 static int find_apple_resolution(int xsize, int ysize)
245 {
246 int apple_id;
247 if (xsize < 800)
248 apple_id = APPLE_640x480;
249 else if (xsize < 1024)
250 apple_id = APPLE_800x600;
251 else if (xsize < 1152)
252 apple_id = APPLE_1024x768;
253 else if (xsize < 1280) {
254 if (ysize < 900)
255 apple_id = APPLE_1152x768;
256 else
257 apple_id = APPLE_1152x900;
258 }
259 else if (xsize < 1600)
260 apple_id = APPLE_1280x1024;
261 else
262 apple_id = APPLE_1600x1200;
263 return apple_id;
264 }
265
266 // Set parameters to specified Apple mode
267 static void set_apple_resolution(int apple_id, int &xsize, int &ysize)
268 {
269 switch (apple_id) {
270 case APPLE_640x480:
271 xsize = 640;
272 ysize = 480;
273 break;
274 case APPLE_800x600:
275 xsize = 800;
276 ysize = 600;
277 break;
278 case APPLE_1024x768:
279 xsize = 1024;
280 ysize = 768;
281 break;
282 case APPLE_1152x768:
283 xsize = 1152;
284 ysize = 768;
285 break;
286 case APPLE_1152x900:
287 xsize = 1152;
288 ysize = 900;
289 break;
290 case APPLE_1280x1024:
291 xsize = 1280;
292 ysize = 1024;
293 break;
294 case APPLE_1600x1200:
295 xsize = 1600;
296 ysize = 1200;
297 break;
298 default:
299 abort();
300 }
301 }
302
303 // Match Apple mode matching best specified dimensions
304 static int match_apple_resolution(int &xsize, int &ysize)
305 {
306 int apple_id = find_apple_resolution(xsize, ysize);
307 set_apple_resolution(apple_id, xsize, ysize);
308 return apple_id;
309 }
310
311 // Display error alert
312 static void ErrorAlert(int error)
313 {
314 ErrorAlert(GetString(error));
315 }
316
317 // Display warning alert
318 static void WarningAlert(int warning)
319 {
320 WarningAlert(GetString(warning));
321 }
322 #endif
323
324
325 /*
326 * monitor_desc subclass for SDL display
327 */
328
329 class SDL_monitor_desc : public monitor_desc {
330 public:
331 SDL_monitor_desc(const vector<VIDEO_MODE> &available_modes, video_depth default_depth, uint32 default_id) : monitor_desc(available_modes, default_depth, default_id) {}
332 ~SDL_monitor_desc() {}
333
334 virtual void switch_to_current_mode(void);
335 virtual void set_palette(uint8 *pal, int num);
336
337 bool video_open(void);
338 void video_close(void);
339 };
340
341
342 /*
343 * Utility functions
344 */
345
346 // Find palette size for given color depth
347 static int palette_size(int mode)
348 {
349 switch (mode) {
350 case VIDEO_DEPTH_1BIT: return 2;
351 case VIDEO_DEPTH_2BIT: return 4;
352 case VIDEO_DEPTH_4BIT: return 16;
353 case VIDEO_DEPTH_8BIT: return 256;
354 case VIDEO_DEPTH_16BIT: return 32;
355 case VIDEO_DEPTH_32BIT: return 256;
356 default: return 0;
357 }
358 }
359
360 // Return bytes per pixel for requested depth
361 static inline int bytes_per_pixel(int depth)
362 {
363 int bpp;
364 switch (depth) {
365 case 8:
366 bpp = 1;
367 break;
368 case 15: case 16:
369 bpp = 2;
370 break;
371 case 24: case 32:
372 bpp = 4;
373 break;
374 default:
375 abort();
376 }
377 return bpp;
378 }
379
380 // Map video_mode depth ID to numerical depth value
381 static int mac_depth_of_video_depth(int video_depth)
382 {
383 int depth = -1;
384 switch (video_depth) {
385 case VIDEO_DEPTH_1BIT:
386 depth = 1;
387 break;
388 case VIDEO_DEPTH_2BIT:
389 depth = 2;
390 break;
391 case VIDEO_DEPTH_4BIT:
392 depth = 4;
393 break;
394 case VIDEO_DEPTH_8BIT:
395 depth = 8;
396 break;
397 case VIDEO_DEPTH_16BIT:
398 depth = 16;
399 break;
400 case VIDEO_DEPTH_32BIT:
401 depth = 32;
402 break;
403 default:
404 abort();
405 }
406 return depth;
407 }
408
409 // Map video_mode depth ID to SDL screen depth
410 static int sdl_depth_of_video_depth(int video_depth)
411 {
412 return (video_depth <= VIDEO_DEPTH_8BIT) ? 8 : mac_depth_of_video_depth(video_depth);
413 }
414
415 // Check wether specified mode is available
416 static bool has_mode(int type, int width, int height)
417 {
418 #ifdef SHEEPSHAVER
419 // Filter out Classic resolutiosn
420 if (width == 512 && height == 384)
421 return false;
422
423 // "screen" prefs items always succeeds
424 if (PrefsFindString("screen"))
425 return true;
426
427 // Read window & screen modes prefs
428 static uint32 window_modes = 0;
429 static uint32 screen_modes = 0;
430 if (window_modes == 0 || screen_modes == 0) {
431 window_modes = PrefsFindInt32("windowmodes");
432 screen_modes = PrefsFindInt32("screenmodes");
433 if (window_modes == 0 || screen_modes == 0)
434 window_modes |= 3; // Allow at least 640x480 and 800x600 window modes
435 }
436
437 int test_modes;
438 switch (type) {
439 case DISPLAY_WINDOW:
440 test_modes = window_modes;
441 break;
442 case DISPLAY_SCREEN:
443 test_modes = screen_modes;
444 break;
445 default:
446 test_modes = 0;
447 break;
448 }
449
450 int apple_mask;
451 switch (find_apple_resolution(width, height)) {
452 case APPLE_640x480: apple_mask = 0x01; break;
453 case APPLE_800x600: apple_mask = 0x02; break;
454 case APPLE_1024x768: apple_mask = 0x04; break;
455 case APPLE_1152x768: apple_mask = 0x40; break;
456 case APPLE_1152x900: apple_mask = 0x08; break;
457 case APPLE_1280x1024: apple_mask = 0x10; break;
458 case APPLE_1600x1200: apple_mask = 0x20; break;
459 default: apple_mask = 0x00; break;
460 }
461 return (test_modes & apple_mask);
462 #endif
463 return true;
464 }
465
466 // Add mode to list of supported modes
467 static void add_mode(int type, int width, int height, int resolution_id, int bytes_per_row, int depth)
468 {
469 // Filter out unsupported modes
470 if (!has_mode(type, width, height))
471 return;
472
473 // Fill in VideoMode entry
474 VIDEO_MODE mode;
475 #ifdef SHEEPSHAVER
476 // Recalculate dimensions to fit Apple modes
477 resolution_id = match_apple_resolution(width, height);
478 mode.viType = type;
479 #endif
480 VIDEO_MODE_X = width;
481 VIDEO_MODE_Y = height;
482 VIDEO_MODE_RESOLUTION = resolution_id;
483 VIDEO_MODE_ROW_BYTES = bytes_per_row;
484 VIDEO_MODE_DEPTH = (video_depth)depth;
485 VideoModes.push_back(mode);
486 }
487
488 // Add standard list of windowed modes for given color depth
489 static void add_window_modes(int depth)
490 {
491 video_depth vdepth = (video_depth)depth;
492 add_mode(DISPLAY_WINDOW, 512, 384, 0x80, TrivialBytesPerRow(512, vdepth), depth);
493 add_mode(DISPLAY_WINDOW, 640, 480, 0x81, TrivialBytesPerRow(640, vdepth), depth);
494 add_mode(DISPLAY_WINDOW, 800, 600, 0x82, TrivialBytesPerRow(800, vdepth), depth);
495 add_mode(DISPLAY_WINDOW, 1024, 768, 0x83, TrivialBytesPerRow(1024, vdepth), depth);
496 add_mode(DISPLAY_WINDOW, 1152, 870, 0x84, TrivialBytesPerRow(1152, vdepth), depth);
497 add_mode(DISPLAY_WINDOW, 1280, 1024, 0x85, TrivialBytesPerRow(1280, vdepth), depth);
498 add_mode(DISPLAY_WINDOW, 1600, 1200, 0x86, TrivialBytesPerRow(1600, vdepth), depth);
499 }
500
501 // Set Mac frame layout and base address (uses the_buffer/MacFrameBaseMac)
502 static void set_mac_frame_buffer(SDL_monitor_desc &monitor, int depth, bool native_byte_order)
503 {
504 #if !REAL_ADDRESSING && !DIRECT_ADDRESSING
505 int layout = FLAYOUT_DIRECT;
506 if (depth == VIDEO_DEPTH_16BIT)
507 layout = (screen_depth == 15) ? FLAYOUT_HOST_555 : FLAYOUT_HOST_565;
508 else if (depth == VIDEO_DEPTH_32BIT)
509 layout = (screen_depth == 24) ? FLAYOUT_HOST_888 : FLAYOUT_DIRECT;
510 if (native_byte_order)
511 MacFrameLayout = layout;
512 else
513 MacFrameLayout = FLAYOUT_DIRECT;
514 monitor.set_mac_frame_base(MacFrameBaseMac);
515
516 // Set variables used by UAE memory banking
517 const VIDEO_MODE &mode = monitor.get_current_mode();
518 MacFrameBaseHost = the_buffer;
519 MacFrameSize = VIDEO_MODE_ROW_BYTES * VIDEO_MODE_Y;
520 InitFrameBufferMapping();
521 #else
522 monitor.set_mac_frame_base(Host2MacAddr(the_buffer));
523 #endif
524 D(bug("monitor.mac_frame_base = %08x\n", monitor.get_mac_frame_base()));
525 }
526
527 // Set window name and class
528 static void set_window_name(int name)
529 {
530 const SDL_VideoInfo *vi = SDL_GetVideoInfo();
531 if (vi && vi->wm_available) {
532 const char *str = GetString(name);
533 SDL_WM_SetCaption(str, str);
534 }
535 }
536
537 // Set mouse grab mode
538 static SDL_GrabMode set_grab_mode(SDL_GrabMode mode)
539 {
540 const SDL_VideoInfo *vi = SDL_GetVideoInfo();
541 return (vi && vi->wm_available ? SDL_WM_GrabInput(mode) : SDL_GRAB_OFF);
542 }
543
544
545 /*
546 * Display "driver" classes
547 */
548
549 class driver_base {
550 public:
551 driver_base(SDL_monitor_desc &m);
552 virtual ~driver_base();
553
554 virtual void update_palette(void);
555 virtual void suspend(void) {}
556 virtual void resume(void) {}
557 virtual void toggle_mouse_grab(void) {}
558 virtual void mouse_moved(int x, int y) { ADBMouseMoved(x, y); }
559
560 void disable_mouse_accel(void);
561 void restore_mouse_accel(void);
562
563 virtual void grab_mouse(void) {}
564 virtual void ungrab_mouse(void) {}
565
566 public:
567 SDL_monitor_desc &monitor; // Associated video monitor
568 const VIDEO_MODE &mode; // Video mode handled by the driver
569
570 bool init_ok; // Initialization succeeded (we can't use exceptions because of -fomit-frame-pointer)
571 SDL_Surface *s; // The surface we draw into
572 };
573
574 class driver_window;
575 static void update_display_window_vosf(driver_window *drv);
576 static void update_display_dynamic(int ticker, driver_window *drv);
577 static void update_display_static(driver_window *drv);
578
579 class driver_window : public driver_base {
580 friend void update_display_window_vosf(driver_window *drv);
581 friend void update_display_dynamic(int ticker, driver_window *drv);
582 friend void update_display_static(driver_window *drv);
583
584 public:
585 driver_window(SDL_monitor_desc &monitor);
586 ~driver_window();
587
588 void toggle_mouse_grab(void);
589 void mouse_moved(int x, int y);
590
591 void grab_mouse(void);
592 void ungrab_mouse(void);
593
594 private:
595 bool mouse_grabbed; // Flag: mouse pointer grabbed, using relative mouse mode
596 int mouse_last_x, mouse_last_y; // Last mouse position (for relative mode)
597 };
598
599 class driver_fullscreen : public driver_base {
600 public:
601 driver_fullscreen(SDL_monitor_desc &monitor);
602 ~driver_fullscreen();
603 };
604
605 static driver_base *drv = NULL; // Pointer to currently used driver object
606
607 #ifdef ENABLE_VOSF
608 # include "video_vosf.h"
609 #endif
610
611 driver_base::driver_base(SDL_monitor_desc &m)
612 : monitor(m), mode(m.get_current_mode()), init_ok(false), s(NULL)
613 {
614 the_buffer = NULL;
615 the_buffer_copy = NULL;
616 }
617
618 driver_base::~driver_base()
619 {
620 ungrab_mouse();
621 restore_mouse_accel();
622
623 if (s)
624 SDL_FreeSurface(s);
625
626 // the_buffer shall always be mapped through vm_acquire_framebuffer()
627 if (the_buffer != VM_MAP_FAILED) {
628 D(bug(" releasing the_buffer at %p (%d bytes)\n", the_buffer, the_buffer_size));
629 vm_release_framebuffer(the_buffer, the_buffer_size);
630 the_buffer = NULL;
631 }
632
633 // Free frame buffer(s)
634 if (!use_vosf) {
635 if (the_buffer_copy) {
636 free(the_buffer_copy);
637 the_buffer_copy = NULL;
638 }
639 }
640 #ifdef ENABLE_VOSF
641 else {
642 if (the_host_buffer) {
643 D(bug(" freeing the_host_buffer at %p\n", the_host_buffer));
644 free(the_host_buffer);
645 the_host_buffer = NULL;
646 }
647 if (the_buffer_copy) {
648 D(bug(" freeing the_buffer_copy at %p\n", the_buffer_copy));
649 free(the_buffer_copy);
650 the_buffer_copy = NULL;
651 }
652
653 // Deinitialize VOSF
654 video_vosf_exit();
655 }
656 #endif
657 }
658
659 // Palette has changed
660 void driver_base::update_palette(void)
661 {
662 const VIDEO_MODE &mode = monitor.get_current_mode();
663
664 if ((int)VIDEO_MODE_DEPTH <= VIDEO_DEPTH_8BIT)
665 SDL_SetPalette(s, SDL_PHYSPAL, sdl_palette, 0, 256);
666 }
667
668 // Disable mouse acceleration
669 void driver_base::disable_mouse_accel(void)
670 {
671 }
672
673 // Restore mouse acceleration to original value
674 void driver_base::restore_mouse_accel(void)
675 {
676 }
677
678
679 /*
680 * Windowed display driver
681 */
682
683 // Open display
684 driver_window::driver_window(SDL_monitor_desc &m)
685 : driver_base(m), mouse_grabbed(false)
686 {
687 int width = VIDEO_MODE_X, height = VIDEO_MODE_Y;
688 int aligned_width = (width + 15) & ~15;
689 int aligned_height = (height + 15) & ~15;
690
691 // Set absolute mouse mode
692 ADBSetRelMouseMode(mouse_grabbed);
693
694 // Create surface
695 int depth = sdl_depth_of_video_depth(VIDEO_MODE_DEPTH);
696 if ((s = SDL_SetVideoMode(width, height, depth, SDL_HWSURFACE)) == NULL)
697 return;
698
699 #ifdef ENABLE_VOSF
700 use_vosf = true;
701 // Allocate memory for frame buffer (SIZE is extended to page-boundary)
702 the_host_buffer = (uint8 *)s->pixels;
703 the_buffer_size = page_extend((aligned_height + 2) * s->pitch);
704 the_buffer = (uint8 *)vm_acquire_framebuffer(the_buffer_size);
705 the_buffer_copy = (uint8 *)malloc(the_buffer_size);
706 D(bug("the_buffer = %p, the_buffer_copy = %p, the_host_buffer = %p\n", the_buffer, the_buffer_copy, the_host_buffer));
707
708 // Check whether we can initialize the VOSF subsystem and it's profitable
709 if (!video_vosf_init(m)) {
710 WarningAlert(STR_VOSF_INIT_ERR);
711 use_vosf = false;
712 }
713 else if (!video_vosf_profitable()) {
714 video_vosf_exit();
715 printf("VOSF acceleration is not profitable on this platform, disabling it\n");
716 use_vosf = false;
717 }
718 if (!use_vosf) {
719 free(the_buffer_copy);
720 vm_release(the_buffer, the_buffer_size);
721 the_host_buffer = NULL;
722 }
723 #endif
724 if (!use_vosf) {
725 // Allocate memory for frame buffer
726 the_buffer_size = (aligned_height + 2) * s->pitch;
727 the_buffer_copy = (uint8 *)calloc(1, the_buffer_size);
728 the_buffer = (uint8 *)vm_acquire_framebuffer(the_buffer_size);
729 D(bug("the_buffer = %p, the_buffer_copy = %p\n", the_buffer, the_buffer_copy));
730 }
731
732 #ifdef SHEEPSHAVER
733 // Create cursor
734 if ((sdl_cursor = SDL_CreateCursor(MacCursor + 4, MacCursor + 36, 16, 16, 0, 0)) != NULL) {
735 SDL_SetCursor(sdl_cursor);
736 cursor_changed = false;
737 }
738 #else
739 // Hide cursor
740 SDL_ShowCursor(0);
741 #endif
742
743 // Set window name/class
744 set_window_name(STR_WINDOW_TITLE);
745
746 // Init blitting routines
747 SDL_PixelFormat *f = s->format;
748 VisualFormat visualFormat;
749 visualFormat.depth = depth;
750 visualFormat.Rmask = f->Rmask;
751 visualFormat.Gmask = f->Gmask;
752 visualFormat.Bmask = f->Bmask;
753 Screen_blitter_init(visualFormat, true, mac_depth_of_video_depth(VIDEO_MODE_DEPTH));
754
755 // Load gray ramp to 8->16/32 expand map
756 if (!IsDirectMode(mode))
757 for (int i=0; i<256; i++)
758 ExpandMap[i] = SDL_MapRGB(f, i, i, i);
759
760 // Set frame buffer base
761 set_mac_frame_buffer(monitor, VIDEO_MODE_DEPTH, true);
762
763 // Everything went well
764 init_ok = true;
765 }
766
767 // Close display
768 driver_window::~driver_window()
769 {
770 #ifdef ENABLE_VOSF
771 if (use_vosf)
772 the_host_buffer = NULL; // don't free() in driver_base dtor
773 #endif
774 if (s)
775 SDL_FreeSurface(s);
776 }
777
778 // Toggle mouse grab
779 void driver_window::toggle_mouse_grab(void)
780 {
781 if (mouse_grabbed)
782 ungrab_mouse();
783 else
784 grab_mouse();
785 }
786
787 // Grab mouse, switch to relative mouse mode
788 void driver_window::grab_mouse(void)
789 {
790 if (!mouse_grabbed) {
791 SDL_GrabMode new_mode = set_grab_mode(SDL_GRAB_ON);
792 if (new_mode == SDL_GRAB_ON) {
793 set_window_name(STR_WINDOW_TITLE_GRABBED);
794 disable_mouse_accel();
795 mouse_grabbed = true;
796 }
797 }
798 }
799
800 // Ungrab mouse, switch to absolute mouse mode
801 void driver_window::ungrab_mouse(void)
802 {
803 if (mouse_grabbed) {
804 SDL_GrabMode new_mode = set_grab_mode(SDL_GRAB_OFF);
805 if (new_mode == SDL_GRAB_OFF) {
806 set_window_name(STR_WINDOW_TITLE);
807 restore_mouse_accel();
808 mouse_grabbed = false;
809 }
810 }
811 }
812
813 // Mouse moved
814 void driver_window::mouse_moved(int x, int y)
815 {
816 mouse_last_x = x; mouse_last_y = y;
817 ADBMouseMoved(x, y);
818 }
819
820
821 /*
822 * Full-screen display driver
823 */
824
825 // Open display
826 driver_fullscreen::driver_fullscreen(SDL_monitor_desc &m)
827 : driver_base(m)
828 {
829 int width = VIDEO_MODE_X, height = VIDEO_MODE_Y;
830 int aligned_width = (width + 15) & ~15;
831 int aligned_height = (height + 15) & ~15;
832
833 // Set absolute mouse mode
834 ADBSetRelMouseMode(false);
835
836 // Create surface
837 int depth = sdl_depth_of_video_depth(VIDEO_MODE_DEPTH);
838 if ((s = SDL_SetVideoMode(width, height, depth, SDL_HWSURFACE | SDL_FULLSCREEN)) == NULL)
839 return;
840
841 #ifdef ENABLE_VOSF
842 use_vosf = true;
843 // Allocate memory for frame buffer (SIZE is extended to page-boundary)
844 the_host_buffer = (uint8 *)s->pixels;
845 the_buffer_size = page_extend((aligned_height + 2) * s->pitch);
846 the_buffer = (uint8 *)vm_acquire_framebuffer(the_buffer_size);
847 the_buffer_copy = (uint8 *)malloc(the_buffer_size);
848 D(bug("the_buffer = %p, the_buffer_copy = %p, the_host_buffer = %p\n", the_buffer, the_buffer_copy, the_host_buffer));
849
850 // Check whether we can initialize the VOSF subsystem and it's profitable
851 if (!video_vosf_init(m)) {
852 WarningAlert(STR_VOSF_INIT_ERR);
853 use_vosf = false;
854 }
855 else if (!video_vosf_profitable()) {
856 video_vosf_exit();
857 printf("VOSF acceleration is not profitable on this platform, disabling it\n");
858 use_vosf = false;
859 }
860 if (!use_vosf) {
861 free(the_buffer_copy);
862 vm_release(the_buffer, the_buffer_size);
863 the_host_buffer = NULL;
864 }
865 #endif
866 if (!use_vosf) {
867 // Allocate memory for frame buffer
868 the_buffer_size = (aligned_height + 2) * s->pitch;
869 the_buffer_copy = (uint8 *)calloc(1, the_buffer_size);
870 the_buffer = (uint8 *)vm_acquire_framebuffer(the_buffer_size);
871 D(bug("the_buffer = %p, the_buffer_copy = %p\n", the_buffer, the_buffer_copy));
872 }
873
874 // Hide cursor
875 SDL_ShowCursor(0);
876
877 // Init blitting routines
878 SDL_PixelFormat *f = s->format;
879 VisualFormat visualFormat;
880 visualFormat.depth = depth;
881 visualFormat.Rmask = f->Rmask;
882 visualFormat.Gmask = f->Gmask;
883 visualFormat.Bmask = f->Bmask;
884 Screen_blitter_init(visualFormat, true, mac_depth_of_video_depth(VIDEO_MODE_DEPTH));
885
886 // Load gray ramp to 8->16/32 expand map
887 if (!IsDirectMode(mode))
888 for (int i=0; i<256; i++)
889 ExpandMap[i] = SDL_MapRGB(f, i, i, i);
890
891 // Set frame buffer base
892 set_mac_frame_buffer(monitor, VIDEO_MODE_DEPTH, true);
893
894 // Everything went well
895 init_ok = true;
896 }
897
898 // Close display
899 driver_fullscreen::~driver_fullscreen()
900 {
901 #ifdef ENABLE_VOSF
902 if (use_vosf)
903 the_host_buffer = NULL; // don't free() in driver_base dtor
904 #endif
905 if (s)
906 SDL_FreeSurface(s);
907
908 // Show cursor
909 SDL_ShowCursor(1);
910 }
911
912
913 /*
914 * Initialization
915 */
916
917 // Init keycode translation table
918 static void keycode_init(void)
919 {
920 bool use_kc = PrefsFindBool("keycodes");
921 if (use_kc) {
922
923 // Get keycode file path from preferences
924 const char *kc_path = PrefsFindString("keycodefile");
925
926 // Open keycode table
927 FILE *f = fopen(kc_path ? kc_path : KEYCODE_FILE_NAME, "r");
928 if (f == NULL) {
929 char str[256];
930 sprintf(str, GetString(STR_KEYCODE_FILE_WARN), kc_path ? kc_path : KEYCODE_FILE_NAME, strerror(errno));
931 WarningAlert(str);
932 return;
933 }
934
935 // Default translation table
936 for (int i=0; i<256; i++)
937 keycode_table[i] = -1;
938
939 // Search for server vendor string, then read keycodes
940 char video_driver[256];
941 SDL_VideoDriverName(video_driver, sizeof(video_driver));
942 bool video_driver_found = false;
943 char line[256];
944 int n_keys = 0;
945 while (fgets(line, sizeof(line) - 1, f)) {
946 // Read line
947 int len = strlen(line);
948 if (len == 0)
949 continue;
950 line[len-1] = 0;
951
952 // Comments begin with "#" or ";"
953 if (line[0] == '#' || line[0] == ';' || line[0] == 0)
954 continue;
955
956 if (video_driver_found) {
957 // Skip aliases as long as we have read keycodes yet
958 // Otherwise, it's another mapping and we have to stop
959 static const char sdl_str[] = "sdl";
960 if (strncmp(line, sdl_str, sizeof(sdl_str) - 1) == 0 && n_keys == 0)
961 continue;
962
963 // Read keycode
964 int x_code, mac_code;
965 if (sscanf(line, "%d %d", &x_code, &mac_code) == 2)
966 keycode_table[x_code & 0xff] = mac_code, n_keys++;
967 else
968 break;
969 } else {
970 // Search for SDL video driver string
971 static const char sdl_str[] = "sdl";
972 if (strncmp(line, sdl_str, sizeof(sdl_str) - 1) == 0) {
973 char *p = line + sizeof(sdl_str);
974 if (strstr(video_driver, p) == video_driver)
975 video_driver_found = true;
976 }
977 }
978 }
979
980 // Keycode file completely read
981 fclose(f);
982 use_keycodes = video_driver_found;
983
984 // Vendor not found? Then display warning
985 if (!video_driver_found) {
986 char str[256];
987 sprintf(str, GetString(STR_KEYCODE_VENDOR_WARN), video_driver, kc_path ? kc_path : KEYCODE_FILE_NAME);
988 WarningAlert(str);
989 return;
990 }
991
992 D(bug("Using SDL/%s keycodes table, %d key mappings\n", video_driver, n_keys));
993 }
994 }
995
996 // Open display for current mode
997 bool SDL_monitor_desc::video_open(void)
998 {
999 D(bug("video_open()\n"));
1000 const VIDEO_MODE &mode = get_current_mode();
1001 #if DEBUG
1002 D(bug("Current video mode:\n"));
1003 D(bug(" %dx%d (ID %02x), %d bpp\n", VIDEO_MODE_X, VIDEO_MODE_Y, VIDEO_MODE_RESOLUTION, 1 << (VIDEO_MODE_DEPTH & 0x0f)));
1004 #endif
1005
1006 // Create display driver object of requested type
1007 switch (display_type) {
1008 case DISPLAY_WINDOW:
1009 drv = new(std::nothrow) driver_window(*this);
1010 break;
1011 case DISPLAY_SCREEN:
1012 drv = new(std::nothrow) driver_fullscreen(*this);
1013 break;
1014 }
1015 if (drv == NULL)
1016 return false;
1017 if (!drv->init_ok) {
1018 delete drv;
1019 drv = NULL;
1020 return false;
1021 }
1022
1023 // Initialize VideoRefresh function
1024 VideoRefreshInit();
1025
1026 // Lock down frame buffer
1027 LOCK_FRAME_BUFFER;
1028
1029 // Start redraw/input thread
1030 #ifndef USE_CPU_EMUL_SERVICES
1031 redraw_thread_cancel = false;
1032 redraw_thread_active = ((redraw_thread = SDL_CreateThread(redraw_func, NULL)) != NULL);
1033 if (!redraw_thread_active) {
1034 printf("FATAL: cannot create redraw thread\n");
1035 return false;
1036 }
1037 #else
1038 redraw_thread_active = true;
1039 #endif
1040 return true;
1041 }
1042
1043 #ifdef SHEEPSHAVER
1044 bool VideoInit(void)
1045 {
1046 const bool classic = false;
1047 #else
1048 bool VideoInit(bool classic)
1049 {
1050 #endif
1051 classic_mode = classic;
1052
1053 #ifdef ENABLE_VOSF
1054 // Zero the mainBuffer structure
1055 mainBuffer.dirtyPages = NULL;
1056 mainBuffer.pageInfo = NULL;
1057 #endif
1058
1059 // Create Mutexes
1060 if ((sdl_palette_lock = SDL_CreateMutex()) == NULL)
1061 return false;
1062 if ((frame_buffer_lock = SDL_CreateMutex()) == NULL)
1063 return false;
1064
1065 // Init keycode translation
1066 keycode_init();
1067
1068 // Read prefs
1069 frame_skip = PrefsFindInt32("frameskip");
1070 mouse_wheel_mode = PrefsFindInt32("mousewheelmode");
1071 mouse_wheel_lines = PrefsFindInt32("mousewheellines");
1072
1073 // Get screen mode from preferences
1074 const char *mode_str = NULL;
1075 if (classic_mode)
1076 mode_str = "win/512/342";
1077 else
1078 mode_str = PrefsFindString("screen");
1079
1080 // Determine display type and default dimensions
1081 int default_width, default_height;
1082 if (classic) {
1083 default_width = 512;
1084 default_height = 384;
1085 }
1086 else {
1087 default_width = 640;
1088 default_height = 480;
1089 }
1090 display_type = DISPLAY_WINDOW;
1091 if (mode_str) {
1092 if (sscanf(mode_str, "win/%d/%d", &default_width, &default_height) == 2)
1093 display_type = DISPLAY_WINDOW;
1094 else if (sscanf(mode_str, "dga/%d/%d", &default_width, &default_height) == 2)
1095 display_type = DISPLAY_SCREEN;
1096 }
1097 int max_width = 640, max_height = 480;
1098 SDL_Rect **modes = SDL_ListModes(NULL, SDL_FULLSCREEN | SDL_HWSURFACE);
1099 if (modes && modes != (SDL_Rect **)-1) {
1100 // It turns out that on some implementations, and contrary to the documentation,
1101 // the returned list is not sorted from largest to smallest (e.g. Windows)
1102 for (int i = 0; modes[i] != NULL; i++) {
1103 const int w = modes[i]->w;
1104 const int h = modes[i]->h;
1105 if (w > max_width && h > max_height) {
1106 max_width = w;
1107 max_height = h;
1108 }
1109 }
1110 if (default_width > max_width)
1111 default_width = max_width;
1112 if (default_height > max_height)
1113 default_height = max_height;
1114 }
1115 if (default_width <= 0)
1116 default_width = max_width;
1117 if (default_height <= 0)
1118 default_height = max_height;
1119
1120 // Mac screen depth follows X depth
1121 screen_depth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
1122 int default_depth;
1123 switch (screen_depth) {
1124 case 8:
1125 default_depth = VIDEO_DEPTH_8BIT;
1126 break;
1127 case 15: case 16:
1128 default_depth = VIDEO_DEPTH_16BIT;
1129 break;
1130 case 24: case 32:
1131 default_depth = VIDEO_DEPTH_32BIT;
1132 break;
1133 default:
1134 default_depth = VIDEO_DEPTH_1BIT;
1135 break;
1136 }
1137
1138 // Construct list of supported modes
1139 if (display_type == DISPLAY_WINDOW) {
1140 if (classic)
1141 add_mode(display_type, 512, 342, 0x80, 64, VIDEO_DEPTH_1BIT);
1142 else {
1143 for (int d = VIDEO_DEPTH_1BIT; d <= default_depth; d++) {
1144 int bpp = sdl_depth_of_video_depth(d);
1145 if (SDL_VideoModeOK(max_width, max_height, bpp, SDL_HWSURFACE))
1146 add_window_modes(video_depth(d));
1147 }
1148 }
1149 } else if (display_type == DISPLAY_SCREEN) {
1150 struct {
1151 int w;
1152 int h;
1153 int resolution_id;
1154 }
1155 video_modes[] = {
1156 { -1, -1, 0x80 },
1157 { 640, 480, 0x81 },
1158 { 800, 600, 0x82 },
1159 { 1024, 768, 0x83 },
1160 { 1152, 870, 0x84 },
1161 { 1280, 1024, 0x85 },
1162 { 1600, 1200, 0x86 },
1163 { 0, }
1164 };
1165 video_modes[0].w = default_width;
1166 video_modes[0].h = default_height;
1167
1168 for (int i = 0; video_modes[i].w != 0; i++) {
1169 const int w = video_modes[i].w;
1170 const int h = video_modes[i].h;
1171 if (i > 0 && (w >= default_width || h >= default_height))
1172 continue;
1173 #ifdef ENABLE_VOSF
1174 for (int d = VIDEO_DEPTH_1BIT; d <= default_depth; d++) {
1175 int bpp = sdl_depth_of_video_depth(d);
1176 if (SDL_VideoModeOK(w, h, bpp, SDL_HWSURFACE | SDL_FULLSCREEN))
1177 add_mode(display_type, w, h, video_modes[i].resolution_id, TrivialBytesPerRow(w, (video_depth)d), d);
1178 }
1179 #else
1180 add_mode(display_type, w, h, video_modes[i].resolution_id, TrivialBytesPerRow(w, (video_depth)default_depth), default_depth);
1181 #endif
1182 }
1183 }
1184
1185 if (VideoModes.empty()) {
1186 ErrorAlert(STR_NO_XVISUAL_ERR);
1187 return false;
1188 }
1189
1190 // Find requested default mode with specified dimensions
1191 uint32 default_id;
1192 std::vector<VIDEO_MODE>::const_iterator i, end = VideoModes.end();
1193 for (i = VideoModes.begin(); i != end; ++i) {
1194 const VIDEO_MODE & mode = (*i);
1195 if (VIDEO_MODE_X == default_width && VIDEO_MODE_Y == default_height && VIDEO_MODE_DEPTH == default_depth) {
1196 default_id = VIDEO_MODE_RESOLUTION;
1197 #ifdef SHEEPSHAVER
1198 std::vector<VIDEO_MODE>::const_iterator begin = VideoModes.begin();
1199 cur_mode = distance(begin, i);
1200 #endif
1201 break;
1202 }
1203 }
1204 if (i == end) { // not found, use first available mode
1205 const VIDEO_MODE & mode = VideoModes[0];
1206 default_depth = VIDEO_MODE_DEPTH;
1207 default_id = VIDEO_MODE_RESOLUTION;
1208 #ifdef SHEEPSHAVER
1209 cur_mode = 0;
1210 #endif
1211 }
1212
1213 #ifdef SHEEPSHAVER
1214 for (int i = 0; i < VideoModes.size(); i++)
1215 VModes[i] = VideoModes[i];
1216 VideoInfo *p = &VModes[VideoModes.size()];
1217 p->viType = DIS_INVALID; // End marker
1218 p->viRowBytes = 0;
1219 p->viXsize = p->viYsize = 0;
1220 p->viAppleMode = 0;
1221 p->viAppleID = 0;
1222 #endif
1223
1224 #if DEBUG
1225 D(bug("Available video modes:\n"));
1226 for (i = VideoModes.begin(); i != end; ++i) {
1227 const VIDEO_MODE & mode = (*i);
1228 int bits = 1 << VIDEO_MODE_DEPTH;
1229 if (bits == 16)
1230 bits = 15;
1231 else if (bits == 32)
1232 bits = 24;
1233 D(bug(" %dx%d (ID %02x), %d colors\n", VIDEO_MODE_X, VIDEO_MODE_Y, VIDEO_MODE_RESOLUTION, 1 << bits));
1234 }
1235 #endif
1236
1237 // Create SDL_monitor_desc for this (the only) display
1238 SDL_monitor_desc *monitor = new SDL_monitor_desc(VideoModes, (video_depth)default_depth, default_id);
1239 VideoMonitors.push_back(monitor);
1240
1241 // Open display
1242 return monitor->video_open();
1243 }
1244
1245
1246 /*
1247 * Deinitialization
1248 */
1249
1250 // Close display
1251 void SDL_monitor_desc::video_close(void)
1252 {
1253 D(bug("video_close()\n"));
1254
1255 // Stop redraw thread
1256 #ifndef USE_CPU_EMUL_SERVICES
1257 if (redraw_thread_active) {
1258 redraw_thread_cancel = true;
1259 SDL_WaitThread(redraw_thread, NULL);
1260 }
1261 #endif
1262 redraw_thread_active = false;
1263
1264 // Unlock frame buffer
1265 UNLOCK_FRAME_BUFFER;
1266 D(bug(" frame buffer unlocked\n"));
1267
1268 // Close display
1269 delete drv;
1270 drv = NULL;
1271 }
1272
1273 void VideoExit(void)
1274 {
1275 // Close displays
1276 vector<monitor_desc *>::iterator i, end = VideoMonitors.end();
1277 for (i = VideoMonitors.begin(); i != end; ++i)
1278 dynamic_cast<SDL_monitor_desc *>(*i)->video_close();
1279
1280 // Destroy locks
1281 if (frame_buffer_lock)
1282 SDL_DestroyMutex(frame_buffer_lock);
1283 if (sdl_palette_lock)
1284 SDL_DestroyMutex(sdl_palette_lock);
1285 }
1286
1287
1288 /*
1289 * Close down full-screen mode (if bringing up error alerts is unsafe while in full-screen mode)
1290 */
1291
1292 void VideoQuitFullScreen(void)
1293 {
1294 D(bug("VideoQuitFullScreen()\n"));
1295 quit_full_screen = true;
1296 }
1297
1298
1299 /*
1300 * Mac VBL interrupt
1301 */
1302
1303 /*
1304 * Execute video VBL routine
1305 */
1306
1307 #ifdef SHEEPSHAVER
1308 void VideoVBL(void)
1309 {
1310 // Emergency quit requested? Then quit
1311 if (emerg_quit)
1312 QuitEmulator();
1313
1314 // Temporarily give up frame buffer lock (this is the point where
1315 // we are suspended when the user presses Ctrl-Tab)
1316 UNLOCK_FRAME_BUFFER;
1317 LOCK_FRAME_BUFFER;
1318
1319 // Execute video VBL
1320 if (private_data != NULL && private_data->interruptsEnabled)
1321 VSLDoInterruptService(private_data->vslServiceID);
1322 }
1323 #else
1324 void VideoInterrupt(void)
1325 {
1326 // We must fill in the events queue in the same thread that did call SDL_SetVideoMode()
1327 SDL_PumpEvents();
1328
1329 // Emergency quit requested? Then quit
1330 if (emerg_quit)
1331 QuitEmulator();
1332
1333 // Temporarily give up frame buffer lock (this is the point where
1334 // we are suspended when the user presses Ctrl-Tab)
1335 UNLOCK_FRAME_BUFFER;
1336 LOCK_FRAME_BUFFER;
1337 }
1338 #endif
1339
1340
1341 /*
1342 * Set palette
1343 */
1344
1345 #ifdef SHEEPSHAVER
1346 void video_set_palette(void)
1347 {
1348 monitor_desc * monitor = VideoMonitors[0];
1349 int n_colors = palette_size(monitor->get_current_mode().viAppleMode);
1350 uint8 pal[256 * 3];
1351 for (int c = 0; c < n_colors; c++) {
1352 pal[c*3 + 0] = mac_pal[c].red;
1353 pal[c*3 + 1] = mac_pal[c].green;
1354 pal[c*3 + 2] = mac_pal[c].blue;
1355 }
1356 monitor->set_palette(pal, n_colors);
1357 }
1358 #endif
1359
1360 void SDL_monitor_desc::set_palette(uint8 *pal, int num_in)
1361 {
1362 const VIDEO_MODE &mode = get_current_mode();
1363
1364 // FIXME: how can we handle the gamma ramp?
1365 if ((int)VIDEO_MODE_DEPTH > VIDEO_DEPTH_8BIT)
1366 return;
1367
1368 LOCK_PALETTE;
1369
1370 // Convert colors to XColor array
1371 int num_out = 256;
1372 bool stretch = false;
1373 SDL_Color *p = sdl_palette;
1374 for (int i=0; i<num_out; i++) {
1375 int c = (stretch ? (i * num_in) / num_out : i);
1376 p->r = pal[c*3 + 0] * 0x0101;
1377 p->g = pal[c*3 + 1] * 0x0101;
1378 p->b = pal[c*3 + 2] * 0x0101;
1379 p++;
1380 }
1381
1382 // Recalculate pixel color expansion map
1383 if (!IsDirectMode(mode)) {
1384 for (int i=0; i<256; i++) {
1385 int c = i & (num_in-1); // If there are less than 256 colors, we repeat the first entries (this makes color expansion easier)
1386 ExpandMap[i] = SDL_MapRGB(drv->s->format, pal[c*3+0], pal[c*3+1], pal[c*3+2]);
1387 }
1388
1389 #ifdef ENABLE_VOSF
1390 if (use_vosf) {
1391 // We have to redraw everything because the interpretation of pixel values changed
1392 LOCK_VOSF;
1393 PFLAG_SET_ALL;
1394 UNLOCK_VOSF;
1395 memset(the_buffer_copy, 0, VIDEO_MODE_ROW_BYTES * VIDEO_MODE_Y);
1396 }
1397 #endif
1398 }
1399
1400 // Tell redraw thread to change palette
1401 sdl_palette_changed = true;
1402
1403 UNLOCK_PALETTE;
1404 }
1405
1406
1407 /*
1408 * Switch video mode
1409 */
1410
1411 #ifdef SHEEPSHAVER
1412 int16 video_mode_change(VidLocals *csSave, uint32 ParamPtr)
1413 {
1414 /* return if no mode change */
1415 if ((csSave->saveData == ReadMacInt32(ParamPtr + csData)) &&
1416 (csSave->saveMode == ReadMacInt16(ParamPtr + csMode))) return noErr;
1417
1418 /* first find video mode in table */
1419 for (int i=0; VModes[i].viType != DIS_INVALID; i++) {
1420 if ((ReadMacInt16(ParamPtr + csMode) == VModes[i].viAppleMode) &&
1421 (ReadMacInt32(ParamPtr + csData) == VModes[i].viAppleID)) {
1422 csSave->saveMode = ReadMacInt16(ParamPtr + csMode);
1423 csSave->saveData = ReadMacInt32(ParamPtr + csData);
1424 csSave->savePage = ReadMacInt16(ParamPtr + csPage);
1425
1426 // Disable interrupts and pause redraw thread
1427 DisableInterrupt();
1428 thread_stop_ack = false;
1429 thread_stop_req = true;
1430 while (!thread_stop_ack) ;
1431
1432 cur_mode = i;
1433 monitor_desc *monitor = VideoMonitors[0];
1434 monitor->switch_to_current_mode();
1435
1436 WriteMacInt32(ParamPtr + csBaseAddr, screen_base);
1437 csSave->saveBaseAddr=screen_base;
1438 csSave->saveData=VModes[cur_mode].viAppleID;/* First mode ... */
1439 csSave->saveMode=VModes[cur_mode].viAppleMode;
1440
1441 // Enable interrupts and resume redraw thread
1442 thread_stop_req = false;
1443 EnableInterrupt();
1444 return noErr;
1445 }
1446 }
1447 return paramErr;
1448 }
1449 #endif
1450
1451 void SDL_monitor_desc::switch_to_current_mode(void)
1452 {
1453 // Close and reopen display
1454 video_close();
1455 video_open();
1456
1457 if (drv == NULL) {
1458 ErrorAlert(STR_OPEN_WINDOW_ERR);
1459 QuitEmulator();
1460 }
1461 }
1462
1463
1464 /*
1465 * Can we set the MacOS cursor image into the window?
1466 */
1467
1468 #ifdef SHEEPSHAVER
1469 bool video_can_change_cursor(void)
1470 {
1471 return (display_type == DISPLAY_WINDOW);
1472 }
1473 #endif
1474
1475
1476 /*
1477 * Set cursor image for window
1478 */
1479
1480 #ifdef SHEEPSHAVER
1481 void video_set_cursor(void)
1482 {
1483 cursor_changed = true;
1484 }
1485 #endif
1486
1487
1488 /*
1489 * Keyboard-related utilify functions
1490 */
1491
1492 static bool is_modifier_key(SDL_KeyboardEvent const & e)
1493 {
1494 switch (e.keysym.sym) {
1495 case SDLK_NUMLOCK:
1496 case SDLK_CAPSLOCK:
1497 case SDLK_SCROLLOCK:
1498 case SDLK_RSHIFT:
1499 case SDLK_LSHIFT:
1500 case SDLK_RCTRL:
1501 case SDLK_LCTRL:
1502 case SDLK_RALT:
1503 case SDLK_LALT:
1504 case SDLK_RMETA:
1505 case SDLK_LMETA:
1506 case SDLK_LSUPER:
1507 case SDLK_RSUPER:
1508 case SDLK_MODE:
1509 case SDLK_COMPOSE:
1510 return true;
1511 }
1512 return false;
1513 }
1514
1515 static bool is_ctrl_down(SDL_keysym const & ks)
1516 {
1517 return ctrl_down || (ks.mod & KMOD_CTRL);
1518 }
1519
1520
1521 /*
1522 * Translate key event to Mac keycode, returns -1 if no keycode was found
1523 * and -2 if the key was recognized as a hotkey
1524 */
1525
1526 static int kc_decode(SDL_keysym const & ks, bool key_down)
1527 {
1528 switch (ks.sym) {
1529 case SDLK_a: return 0x00;
1530 case SDLK_b: return 0x0b;
1531 case SDLK_c: return 0x08;
1532 case SDLK_d: return 0x02;
1533 case SDLK_e: return 0x0e;
1534 case SDLK_f: return 0x03;
1535 case SDLK_g: return 0x05;
1536 case SDLK_h: return 0x04;
1537 case SDLK_i: return 0x22;
1538 case SDLK_j: return 0x26;
1539 case SDLK_k: return 0x28;
1540 case SDLK_l: return 0x25;
1541 case SDLK_m: return 0x2e;
1542 case SDLK_n: return 0x2d;
1543 case SDLK_o: return 0x1f;
1544 case SDLK_p: return 0x23;
1545 case SDLK_q: return 0x0c;
1546 case SDLK_r: return 0x0f;
1547 case SDLK_s: return 0x01;
1548 case SDLK_t: return 0x11;
1549 case SDLK_u: return 0x20;
1550 case SDLK_v: return 0x09;
1551 case SDLK_w: return 0x0d;
1552 case SDLK_x: return 0x07;
1553 case SDLK_y: return 0x10;
1554 case SDLK_z: return 0x06;
1555
1556 case SDLK_1: case SDLK_EXCLAIM: return 0x12;
1557 case SDLK_2: case SDLK_AT: return 0x13;
1558 case SDLK_3: case SDLK_HASH: return 0x14;
1559 case SDLK_4: case SDLK_DOLLAR: return 0x15;
1560 case SDLK_5: return 0x17;
1561 case SDLK_6: return 0x16;
1562 case SDLK_7: return 0x1a;
1563 case SDLK_8: return 0x1c;
1564 case SDLK_9: return 0x19;
1565 case SDLK_0: return 0x1d;
1566
1567 case SDLK_BACKQUOTE: return 0x0a;
1568 case SDLK_MINUS: case SDLK_UNDERSCORE: return 0x1b;
1569 case SDLK_EQUALS: case SDLK_PLUS: return 0x18;
1570 case SDLK_LEFTBRACKET: return 0x21;
1571 case SDLK_RIGHTBRACKET: return 0x1e;
1572 case SDLK_BACKSLASH: return 0x2a;
1573 case SDLK_SEMICOLON: case SDLK_COLON: return 0x29;
1574 case SDLK_QUOTE: case SDLK_QUOTEDBL: return 0x27;
1575 case SDLK_COMMA: case SDLK_LESS: return 0x2b;
1576 case SDLK_PERIOD: case SDLK_GREATER: return 0x2f;
1577 case SDLK_SLASH: case SDLK_QUESTION: return 0x2c;
1578
1579 case SDLK_TAB: if (is_ctrl_down(ks)) {if (!key_down) drv->suspend(); return -2;} else return 0x30;
1580 case SDLK_RETURN: return 0x24;
1581 case SDLK_SPACE: return 0x31;
1582 case SDLK_BACKSPACE: return 0x33;
1583
1584 case SDLK_DELETE: return 0x75;
1585 case SDLK_INSERT: return 0x72;
1586 case SDLK_HOME: case SDLK_HELP: return 0x73;
1587 case SDLK_END: return 0x77;
1588 case SDLK_PAGEUP: return 0x74;
1589 case SDLK_PAGEDOWN: return 0x79;
1590
1591 case SDLK_LCTRL: return 0x36;
1592 case SDLK_RCTRL: return 0x36;
1593 case SDLK_LSHIFT: return 0x38;
1594 case SDLK_RSHIFT: return 0x38;
1595 #if (defined(__APPLE__) && defined(__MACH__))
1596 case SDLK_LALT: return 0x3a;
1597 case SDLK_RALT: return 0x3a;
1598 case SDLK_LMETA: return 0x37;
1599 case SDLK_RMETA: return 0x37;
1600 #else
1601 case SDLK_LALT: return 0x37;
1602 case SDLK_RALT: return 0x37;
1603 case SDLK_LMETA: return 0x3a;
1604 case SDLK_RMETA: return 0x3a;
1605 #endif
1606 case SDLK_LSUPER: return 0x3a; // "Windows" key
1607 case SDLK_RSUPER: return 0x3a;
1608 case SDLK_MENU: return 0x32;
1609 case SDLK_CAPSLOCK: return 0x39;
1610 case SDLK_NUMLOCK: return 0x47;
1611
1612 case SDLK_UP: return 0x3e;
1613 case SDLK_DOWN: return 0x3d;
1614 case SDLK_LEFT: return 0x3b;
1615 case SDLK_RIGHT: return 0x3c;
1616
1617 case SDLK_ESCAPE: if (is_ctrl_down(ks)) {if (!key_down) { quit_full_screen = true; emerg_quit = true; } return -2;} else return 0x35;
1618
1619 case SDLK_F1: if (is_ctrl_down(ks)) {if (!key_down) SysMountFirstFloppy(); return -2;} else return 0x7a;
1620 case SDLK_F2: return 0x78;
1621 case SDLK_F3: return 0x63;
1622 case SDLK_F4: return 0x76;
1623 case SDLK_F5: if (is_ctrl_down(ks)) {if (!key_down) drv->toggle_mouse_grab(); return -2;} else return 0x60;
1624 case SDLK_F6: return 0x61;
1625 case SDLK_F7: return 0x62;
1626 case SDLK_F8: return 0x64;
1627 case SDLK_F9: return 0x65;
1628 case SDLK_F10: return 0x6d;
1629 case SDLK_F11: return 0x67;
1630 case SDLK_F12: return 0x6f;
1631
1632 case SDLK_PRINT: return 0x69;
1633 case SDLK_SCROLLOCK: return 0x6b;
1634 case SDLK_PAUSE: return 0x71;
1635
1636 case SDLK_KP0: return 0x52;
1637 case SDLK_KP1: return 0x53;
1638 case SDLK_KP2: return 0x54;
1639 case SDLK_KP3: return 0x55;
1640 case SDLK_KP4: return 0x56;
1641 case SDLK_KP5: return 0x57;
1642 case SDLK_KP6: return 0x58;
1643 case SDLK_KP7: return 0x59;
1644 case SDLK_KP8: return 0x5b;
1645 case SDLK_KP9: return 0x5c;
1646 case SDLK_KP_PERIOD: return 0x41;
1647 case SDLK_KP_PLUS: return 0x45;
1648 case SDLK_KP_MINUS: return 0x4e;
1649 case SDLK_KP_MULTIPLY: return 0x43;
1650 case SDLK_KP_DIVIDE: return 0x4b;
1651 case SDLK_KP_ENTER: return 0x4c;
1652 case SDLK_KP_EQUALS: return 0x51;
1653 }
1654 D(bug("Unhandled SDL keysym: %d\n", ks.sym));
1655 return -1;
1656 }
1657
1658 static int event2keycode(SDL_KeyboardEvent const &ev, bool key_down)
1659 {
1660 return kc_decode(ev.keysym, key_down);
1661 }
1662
1663
1664 /*
1665 * SDL event handling
1666 */
1667
1668 static void handle_events(void)
1669 {
1670 SDL_Event events[10];
1671 const int n_max_events = sizeof(events) / sizeof(events[0]);
1672 int n_events;
1673
1674 while ((n_events = SDL_PeepEvents(events, n_max_events, SDL_GETEVENT, sdl_eventmask)) > 0) {
1675 for (int i = 0; i < n_events; i++) {
1676 SDL_Event const & event = events[i];
1677 switch (event.type) {
1678
1679 // Mouse button
1680 case SDL_MOUSEBUTTONDOWN: {
1681 unsigned int button = event.button.button;
1682 if (button < 4)
1683 ADBMouseDown(button - 1);
1684 else if (button < 6) { // Wheel mouse
1685 if (mouse_wheel_mode == 0) {
1686 int key = (button == 5) ? 0x79 : 0x74; // Page up/down
1687 ADBKeyDown(key);
1688 ADBKeyUp(key);
1689 } else {
1690 int key = (button == 5) ? 0x3d : 0x3e; // Cursor up/down
1691 for(int i=0; i<mouse_wheel_lines; i++) {
1692 ADBKeyDown(key);
1693 ADBKeyUp(key);
1694 }
1695 }
1696 }
1697 break;
1698 }
1699 case SDL_MOUSEBUTTONUP: {
1700 unsigned int button = event.button.button;
1701 if (button < 4)
1702 ADBMouseUp(button - 1);
1703 break;
1704 }
1705
1706 // Mouse moved
1707 case SDL_MOUSEMOTION:
1708 drv->mouse_moved(event.motion.x, event.motion.y);
1709 break;
1710
1711 // Keyboard
1712 case SDL_KEYDOWN: {
1713 int code = -1;
1714 if (use_keycodes && !is_modifier_key(event.key)) {
1715 if (event2keycode(event.key, true) != -2) // This is called to process the hotkeys
1716 code = keycode_table[event.key.keysym.scancode & 0xff];
1717 } else
1718 code = event2keycode(event.key, true);
1719 if (code >= 0) {
1720 if (!emul_suspended) {
1721 if (code == 0x39) { // Caps Lock pressed
1722 if (caps_on) {
1723 ADBKeyUp(code);
1724 caps_on = false;
1725 } else {
1726 ADBKeyDown(code);
1727 caps_on = true;
1728 }
1729 } else
1730 ADBKeyDown(code);
1731 if (code == 0x36)
1732 ctrl_down = true;
1733 } else {
1734 if (code == 0x31)
1735 drv->resume(); // Space wakes us up
1736 }
1737 }
1738 break;
1739 }
1740 case SDL_KEYUP: {
1741 int code = -1;
1742 if (use_keycodes && !is_modifier_key(event.key)) {
1743 if (event2keycode(event.key, false) != -2) // This is called to process the hotkeys
1744 code = keycode_table[event.key.keysym.scancode & 0xff];
1745 } else
1746 code = event2keycode(event.key, false);
1747 if (code >= 0) {
1748 if (code == 0x39) { // Caps Lock released
1749 if (caps_on) {
1750 ADBKeyUp(code);
1751 caps_on = false;
1752 } else {
1753 ADBKeyDown(code);
1754 caps_on = true;
1755 }
1756 } else
1757 ADBKeyUp(code);
1758 if (code == 0x36)
1759 ctrl_down = false;
1760 }
1761 break;
1762 }
1763
1764 // Hidden parts exposed, force complete refresh of window
1765 case SDL_VIDEOEXPOSE:
1766 if (display_type == DISPLAY_WINDOW) {
1767 const VIDEO_MODE &mode = VideoMonitors[0]->get_current_mode();
1768 #ifdef ENABLE_VOSF
1769 if (use_vosf) { // VOSF refresh
1770 LOCK_VOSF;
1771 PFLAG_SET_ALL;
1772 UNLOCK_VOSF;
1773 memset(the_buffer_copy, 0, VIDEO_MODE_ROW_BYTES * VIDEO_MODE_Y);
1774 }
1775 else
1776 #endif
1777 memset(the_buffer_copy, 0, VIDEO_MODE_ROW_BYTES * VIDEO_MODE_Y);
1778 }
1779 break;
1780
1781 // Window "close" widget clicked
1782 case SDL_QUIT:
1783 ADBKeyDown(0x7f); // Power key
1784 ADBKeyUp(0x7f);
1785 break;
1786 }
1787 }
1788 }
1789 }
1790
1791
1792 /*
1793 * Window display update
1794 */
1795
1796 // Static display update (fixed frame rate, but incremental)
1797 static void update_display_static(driver_window *drv)
1798 {
1799 // Incremental update code
1800 int wide = 0, high = 0, x1, x2, y1, y2, i, j;
1801 const VIDEO_MODE &mode = drv->mode;
1802 int bytes_per_row = VIDEO_MODE_ROW_BYTES;
1803 uint8 *p, *p2;
1804
1805 // Check for first line from top and first line from bottom that have changed
1806 y1 = 0;
1807 for (j=0; j<VIDEO_MODE_Y; j++) {
1808 if (memcmp(&the_buffer[j * bytes_per_row], &the_buffer_copy[j * bytes_per_row], bytes_per_row)) {
1809 y1 = j;
1810 break;
1811 }
1812 }
1813 y2 = y1 - 1;
1814 for (j=VIDEO_MODE_Y-1; j>=y1; j--) {
1815 if (memcmp(&the_buffer[j * bytes_per_row], &the_buffer_copy[j * bytes_per_row], bytes_per_row)) {
1816 y2 = j;
1817 break;
1818 }
1819 }
1820 high = y2 - y1 + 1;
1821
1822 // Check for first column from left and first column from right that have changed
1823 if (high) {
1824 if ((int)VIDEO_MODE_DEPTH < VIDEO_DEPTH_8BIT) {
1825 const int src_bytes_per_row = bytes_per_row;
1826 const int dst_bytes_per_row = drv->s->pitch;
1827 const int pixels_per_byte = VIDEO_MODE_X / src_bytes_per_row;
1828
1829 x1 = VIDEO_MODE_X / pixels_per_byte;
1830 for (j = y1; j <= y2; j++) {
1831 p = &the_buffer[j * bytes_per_row];
1832 p2 = &the_buffer_copy[j * bytes_per_row];
1833 for (i = 0; i < x1; i++) {
1834 if (*p != *p2) {
1835 x1 = i;
1836 break;
1837 }
1838 p++; p2++;
1839 }
1840 }
1841 x2 = x1;
1842 for (j = y1; j <= y2; j++) {
1843 p = &the_buffer[j * bytes_per_row];
1844 p2 = &the_buffer_copy[j * bytes_per_row];
1845 p += bytes_per_row;
1846 p2 += bytes_per_row;
1847 for (i = (VIDEO_MODE_X / pixels_per_byte); i > x2; i--) {
1848 p--; p2--;
1849 if (*p != *p2) {
1850 x2 = i;
1851 break;
1852 }
1853 }
1854 }
1855 x1 *= pixels_per_byte;
1856 x2 *= pixels_per_byte;
1857 wide = (x2 - x1 + pixels_per_byte - 1) & -pixels_per_byte;
1858
1859 // Update copy of the_buffer
1860 if (high && wide) {
1861
1862 // Lock surface, if required
1863 if (SDL_MUSTLOCK(drv->s))
1864 SDL_LockSurface(drv->s);
1865
1866 // Blit to screen surface
1867 int si = y1 * src_bytes_per_row + (x1 / pixels_per_byte);
1868 int di = y1 * dst_bytes_per_row + x1;
1869 for (j = y1; j <= y2; j++) {
1870 memcpy(the_buffer_copy + si, the_buffer + si, wide / pixels_per_byte);
1871 Screen_blit((uint8 *)drv->s->pixels + di, the_buffer + si, wide / pixels_per_byte);
1872 si += src_bytes_per_row;
1873 di += dst_bytes_per_row;
1874 }
1875
1876 // Unlock surface, if required
1877 if (SDL_MUSTLOCK(drv->s))
1878 SDL_UnlockSurface(drv->s);
1879
1880 // Refresh display
1881 SDL_UpdateRect(drv->s, x1, y1, wide, high);
1882 }
1883
1884 } else {
1885 const int bytes_per_pixel = VIDEO_MODE_ROW_BYTES / VIDEO_MODE_X;
1886
1887 x1 = VIDEO_MODE_X;
1888 for (j=y1; j<=y2; j++) {
1889 p = &the_buffer[j * bytes_per_row];
1890 p2 = &the_buffer_copy[j * bytes_per_row];
1891 for (i=0; i<x1*bytes_per_pixel; i++) {
1892 if (*p != *p2) {
1893 x1 = i / bytes_per_pixel;
1894 break;
1895 }
1896 p++; p2++;
1897 }
1898 }
1899 x2 = x1;
1900 for (j=y1; j<=y2; j++) {
1901 p = &the_buffer[j * bytes_per_row];
1902 p2 = &the_buffer_copy[j * bytes_per_row];
1903 p += bytes_per_row;
1904 p2 += bytes_per_row;
1905 for (i=VIDEO_MODE_X*bytes_per_pixel; i>x2*bytes_per_pixel; i--) {
1906 p--;
1907 p2--;
1908 if (*p != *p2) {
1909 x2 = i / bytes_per_pixel;
1910 break;
1911 }
1912 }
1913 }
1914 wide = x2 - x1;
1915
1916 // Update copy of the_buffer
1917 if (high && wide) {
1918
1919 // Lock surface, if required
1920 if (SDL_MUSTLOCK(drv->s))
1921 SDL_LockSurface(drv->s);
1922
1923 // Blit to screen surface
1924 for (j=y1; j<=y2; j++) {
1925 i = j * bytes_per_row + x1 * bytes_per_pixel;
1926 memcpy(the_buffer_copy + i, the_buffer + i, bytes_per_pixel * wide);
1927 Screen_blit((uint8 *)drv->s->pixels + i, the_buffer + i, bytes_per_pixel * wide);
1928 }
1929
1930 // Unlock surface, if required
1931 if (SDL_MUSTLOCK(drv->s))
1932 SDL_UnlockSurface(drv->s);
1933
1934 // Refresh display
1935 SDL_UpdateRect(drv->s, x1, y1, wide, high);
1936 }
1937 }
1938 }
1939 }
1940
1941
1942 // We suggest the compiler to inline the next two functions so that it
1943 // may specialise the code according to the current screen depth and
1944 // display type. A clever compiler would do that job by itself though...
1945
1946 // NOTE: update_display_vosf is inlined too
1947
1948 static inline void possibly_quit_dga_mode()
1949 {
1950 // Quit DGA mode if requested (something terrible has happened and we
1951 // want to give control back to the user)
1952 if (quit_full_screen) {
1953 quit_full_screen = false;
1954 delete drv;
1955 drv = NULL;
1956 }
1957 }
1958
1959 static inline void possibly_ungrab_mouse()
1960 {
1961 // Ungrab mouse if requested (something terrible has happened and we
1962 // want to give control back to the user)
1963 if (quit_full_screen) {
1964 quit_full_screen = false;
1965 if (drv)
1966 drv->ungrab_mouse();
1967 }
1968 }
1969
1970 static inline void handle_palette_changes(void)
1971 {
1972 LOCK_PALETTE;
1973
1974 if (sdl_palette_changed) {
1975 sdl_palette_changed = false;
1976 drv->update_palette();
1977 }
1978
1979 UNLOCK_PALETTE;
1980 }
1981
1982 static void video_refresh_dga(void)
1983 {
1984 // Quit DGA mode if requested
1985 possibly_quit_dga_mode();
1986 }
1987
1988 #ifdef ENABLE_VOSF
1989 #if REAL_ADDRESSING || DIRECT_ADDRESSING
1990 static void video_refresh_dga_vosf(void)
1991 {
1992 // Quit DGA mode if requested
1993 possibly_quit_dga_mode();
1994
1995 // Update display (VOSF variant)
1996 static int tick_counter = 0;
1997 if (++tick_counter >= frame_skip) {
1998 tick_counter = 0;
1999 if (mainBuffer.dirty) {
2000 LOCK_VOSF;
2001 update_display_dga_vosf(static_cast<driver_fullscreen *>(drv));
2002 UNLOCK_VOSF;
2003 }
2004 }
2005 }
2006 #endif
2007
2008 static void video_refresh_window_vosf(void)
2009 {
2010 // Ungrab mouse if requested
2011 possibly_ungrab_mouse();
2012
2013 // Update display (VOSF variant)
2014 static int tick_counter = 0;
2015 if (++tick_counter >= frame_skip) {
2016 tick_counter = 0;
2017 if (mainBuffer.dirty) {
2018 LOCK_VOSF;
2019 update_display_window_vosf(static_cast<driver_window *>(drv));
2020 UNLOCK_VOSF;
2021 }
2022 }
2023 }
2024 #endif // def ENABLE_VOSF
2025
2026 static void video_refresh_window_static(void)
2027 {
2028 // Ungrab mouse if requested
2029 possibly_ungrab_mouse();
2030
2031 // Update display (static variant)
2032 static int tick_counter = 0;
2033 if (++tick_counter >= frame_skip) {
2034 tick_counter = 0;
2035 update_display_static(static_cast<driver_window *>(drv));
2036 }
2037 }
2038
2039
2040 /*
2041 * Thread for screen refresh, input handling etc.
2042 */
2043
2044 static void VideoRefreshInit(void)
2045 {
2046 // TODO: set up specialised 8bpp VideoRefresh handlers ?
2047 if (display_type == DISPLAY_SCREEN) {
2048 #if ENABLE_VOSF && (REAL_ADDRESSING || DIRECT_ADDRESSING)
2049 if (use_vosf)
2050 video_refresh = video_refresh_dga_vosf;
2051 else
2052 #endif
2053 video_refresh = video_refresh_dga;
2054 }
2055 else {
2056 #ifdef ENABLE_VOSF
2057 if (use_vosf)
2058 video_refresh = video_refresh_window_vosf;
2059 else
2060 #endif
2061 video_refresh = video_refresh_window_static;
2062 }
2063 }
2064
2065 static inline void do_video_refresh(void)
2066 {
2067 // Handle SDL events
2068 handle_events();
2069
2070 // Update display
2071 video_refresh();
2072
2073 #ifdef SHEEPSHAVER
2074 // Set new cursor image if it was changed
2075 if (cursor_changed && sdl_cursor) {
2076 cursor_changed = false;
2077 SDL_FreeCursor(sdl_cursor);
2078 sdl_cursor = SDL_CreateCursor(MacCursor + 4, MacCursor + 36, 16, 16, MacCursor[2], MacCursor[3]);
2079 if (sdl_cursor)
2080 SDL_SetCursor(sdl_cursor);
2081 }
2082 #endif
2083
2084 // Set new palette if it was changed
2085 handle_palette_changes();
2086 }
2087
2088 // This function is called on non-threaded platforms from a timer interrupt
2089 void VideoRefresh(void)
2090 {
2091 // We need to check redraw_thread_active to inhibit refreshed during
2092 // mode changes on non-threaded platforms
2093 if (!redraw_thread_active)
2094 return;
2095
2096 // Process pending events and update display
2097 do_video_refresh();
2098 }
2099
2100 const int VIDEO_REFRESH_HZ = 60;
2101 const int VIDEO_REFRESH_DELAY = 1000000 / VIDEO_REFRESH_HZ;
2102
2103 #ifndef USE_CPU_EMUL_SERVICES
2104 static int redraw_func(void *arg)
2105 {
2106 uint64 start = GetTicks_usec();
2107 int64 ticks = 0;
2108 uint64 next = GetTicks_usec() + VIDEO_REFRESH_DELAY;
2109
2110 while (!redraw_thread_cancel) {
2111
2112 // Wait
2113 next += VIDEO_REFRESH_DELAY;
2114 int64 delay = next - GetTicks_usec();
2115 if (delay > 0)
2116 Delay_usec(delay);
2117 else if (delay < -VIDEO_REFRESH_DELAY)
2118 next = GetTicks_usec();
2119 ticks++;
2120
2121 #ifdef SHEEPSHAVER
2122 // Pause if requested (during video mode switches)
2123 if (thread_stop_req) {
2124 thread_stop_ack = true;
2125 continue;
2126 }
2127 #endif
2128
2129 // Process pending events and update display
2130 do_video_refresh();
2131 }
2132
2133 uint64 end = GetTicks_usec();
2134 D(bug("%lld refreshes in %lld usec = %f refreshes/sec\n", ticks, end - start, ticks * 1000000.0 / (end - start)));
2135 return 0;
2136 }
2137 #endif