~ubuntu-branches/ubuntu/feisty/basilisk2/feisty

« back to all changes in this revision

Viewing changes to src/SDL/video_sdl.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonas Smedegaard
  • Date: 2005-07-30 20:42:20 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20050730204220-1nl1cg2jkjvy63ry
Tags: 0.9.20050730-1
* New upstream CVS snapshot.
* Build-depend on virtual libsdl-dev (not libsdl1.2-dev).
* Invoke init rules also on clean (to separate better from official
  builds).
* Update URL of upstream source in debian/copyright.

Show diffs side-by-side

added added

removed removed

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