mirror of
https://github.com/kanjitalk755/macemu.git
synced 2024-12-22 13:30:07 +00:00
- ADB has its own interrupt flag, INTFLAG_ADB
- ADBMouseMoved(), ADBMouseDown/Up() and ADBKeyDown/Up() trigger the ADB interrupt - ADB mutex is only used for mouse movement (the only input state where it matters) - adb.cpp: toggling relative mouse mode resets mouse_x/y - PrimeTime(0) schedules a timer task with 0 delay time; this is still not the correct implementation, but it makes MacSyndicate work... - Unix: pthreads are preferred to POSIX.4 timers for 60Hz ticks because the timers drift badly under Linux and the thread can compensate for drifting well enough - Unix: moved GetTicks_usec() and Delay_usec() to timer_unix.cpp - video_x.cpp: X mouse acceleration is disabled in relative mouse mode because MacOS does its own acceleration - video_x.cpp: palette[].pixel and palette[].flags are always preset - video_x.cpp: decoupled X event handling from 60Hz video refresh cycle by using select() with a timeout on the X fd
This commit is contained in:
parent
8d733ed691
commit
5868a40a37
@ -7,10 +7,15 @@ V1.0 (snapshot) - <date>
|
||||
thread-safe mouse handling
|
||||
- the TIME_OFFSET constant has been replaced by a (portable) function
|
||||
TimeToMacTime(); file dates in ExtFS should now be correct
|
||||
- ADBInterrupt() is no longer called from the 60Hz interrupt but has
|
||||
its own interrupt flag, potentially increasing the smoothness of
|
||||
mouse movement
|
||||
- Unix: windowed display mode supports different resolutions and color
|
||||
depth, which can be switched on-the-fly
|
||||
depths, which can be switched on-the-fly
|
||||
- Unix: Ctrl-F5 grabs mouse in windowed mode (enhanced compatibility
|
||||
with games like flight simulators)
|
||||
- Unix: X11 events are handled as soon as they arrive, outside of the
|
||||
60Hz video refresh raster
|
||||
- Unix: audio sample rate, bit depth and channel count are adjustable
|
||||
in the MacOS "Sound" control panel
|
||||
|
||||
|
@ -616,9 +616,14 @@ Keyboard:
|
||||
On PC-style keyboards, "Alt" is the Mac "Command" key, while the "Windows"
|
||||
key is the Mac "Option" key.
|
||||
|
||||
Mouse:
|
||||
Under Unix, press Ctrl-F5 while the Basilisk II window is active will grab
|
||||
the mouse. This is needed for compatibility with some MacOS programs,
|
||||
especially games. Press Ctrl-F5 again to return to normal mouse operation.
|
||||
|
||||
Floppy:
|
||||
Basilisk II can only handle 1.44MB MFM floppies. Depending on your platform,
|
||||
flopyy disk changes might not be detected automatically. Under Linux, press
|
||||
floppy disk changes might not be detected automatically. Under Unix, press
|
||||
Ctrl-F1 to mount a floppy. Under BeOS, select the appropriate "Mount" menu
|
||||
item or press Ctrl-F1 to mount a floppy. Under Windows, press Ctrl-Shift-F11.
|
||||
|
||||
|
@ -475,7 +475,28 @@ int main(int argc, char **argv)
|
||||
sigaction(SIGINT, &sigint_sa, NULL);
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_TIMER_CREATE) && defined(_POSIX_REALTIME_SIGNALS)
|
||||
#if defined(HAVE_PTHREADS)
|
||||
|
||||
// POSIX threads available, start 60Hz thread
|
||||
pthread_attr_init(&tick_thread_attr);
|
||||
#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
|
||||
if (geteuid() == 0) {
|
||||
pthread_attr_setinheritsched(&tick_thread_attr, PTHREAD_EXPLICIT_SCHED);
|
||||
pthread_attr_setschedpolicy(&tick_thread_attr, SCHED_FIFO);
|
||||
struct sched_param fifo_param;
|
||||
fifo_param.sched_priority = (sched_get_priority_min(SCHED_FIFO) + sched_get_priority_max(SCHED_FIFO)) / 2;
|
||||
pthread_attr_setschedparam(&tick_thread_attr, &fifo_param);
|
||||
}
|
||||
#endif
|
||||
tick_thread_active = (pthread_create(&tick_thread, &tick_thread_attr, tick_func, NULL) == 0);
|
||||
if (!tick_thread_active) {
|
||||
sprintf(str, GetString(STR_TICK_THREAD_ERR), strerror(errno));
|
||||
ErrorAlert(str);
|
||||
QuitEmulator();
|
||||
}
|
||||
D(bug("60Hz thread started\n"));
|
||||
|
||||
#elif defined(HAVE_TIMER_CREATE) && defined(_POSIX_REALTIME_SIGNALS)
|
||||
|
||||
// POSIX.4 timers and real-time signals available, start 60Hz timer
|
||||
sigemptyset(&timer_sa.sa_mask);
|
||||
@ -506,27 +527,6 @@ int main(int argc, char **argv)
|
||||
}
|
||||
D(bug("60Hz timer started\n"));
|
||||
|
||||
#elif defined(HAVE_PTHREADS)
|
||||
|
||||
// POSIX threads available, start 60Hz thread
|
||||
pthread_attr_init(&tick_thread_attr);
|
||||
#if defined(_POSIX_THREAD_PRIORITY_SCHEDULING)
|
||||
if (geteuid() == 0) {
|
||||
pthread_attr_setinheritsched(&tick_thread_attr, PTHREAD_EXPLICIT_SCHED);
|
||||
pthread_attr_setschedpolicy(&tick_thread_attr, SCHED_FIFO);
|
||||
struct sched_param fifo_param;
|
||||
fifo_param.sched_priority = (sched_get_priority_min(SCHED_FIFO) + sched_get_priority_max(SCHED_FIFO)) / 2;
|
||||
pthread_attr_setschedparam(&tick_thread_attr, &fifo_param);
|
||||
}
|
||||
#endif
|
||||
tick_thread_active = (pthread_create(&tick_thread, &tick_thread_attr, tick_func, NULL) == 0);
|
||||
if (!tick_thread_active) {
|
||||
sprintf(str, GetString(STR_TICK_THREAD_ERR), strerror(errno));
|
||||
ErrorAlert(str);
|
||||
QuitEmulator();
|
||||
}
|
||||
D(bug("60Hz thread started\n"));
|
||||
|
||||
#else
|
||||
|
||||
// Start 60Hz timer
|
||||
@ -575,10 +575,7 @@ void QuitEmulator(void)
|
||||
Exit680x0();
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_TIMER_CREATE) && defined(_POSIX_REALTIME_SIGNALS)
|
||||
// Stop 60Hz timer
|
||||
timer_delete(timer);
|
||||
#elif defined(HAVE_PTHREADS)
|
||||
#if defined(HAVE_PTHREADS)
|
||||
// Stop 60Hz thread
|
||||
if (tick_thread_active) {
|
||||
tick_thread_cancel = true;
|
||||
@ -587,6 +584,9 @@ void QuitEmulator(void)
|
||||
#endif
|
||||
pthread_join(tick_thread, NULL);
|
||||
}
|
||||
#elif defined(HAVE_TIMER_CREATE) && defined(_POSIX_REALTIME_SIGNALS)
|
||||
// Stop 60Hz timer
|
||||
timer_delete(timer);
|
||||
#else
|
||||
struct itimerval req;
|
||||
req.it_interval.tv_sec = req.it_value.tv_sec = 0;
|
||||
@ -849,6 +849,8 @@ static void one_tick(...)
|
||||
#ifdef HAVE_PTHREADS
|
||||
static void *tick_func(void *arg)
|
||||
{
|
||||
uint64 start = GetTicks_usec();
|
||||
int64 ticks = 0;
|
||||
uint64 next = GetTicks_usec();
|
||||
while (!tick_thread_cancel) {
|
||||
one_tick();
|
||||
@ -858,110 +860,15 @@ static void *tick_func(void *arg)
|
||||
Delay_usec(delay);
|
||||
else if (delay < -16625)
|
||||
next = GetTicks_usec();
|
||||
ticks++;
|
||||
}
|
||||
uint64 end = GetTicks_usec();
|
||||
D(bug("%Ld ticks in %Ld usec = %f ticks/sec\n", ticks, end - start, ticks * 1000000.0 / (end - start)));
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Get current value of microsecond timer
|
||||
*/
|
||||
|
||||
uint64 GetTicks_usec(void)
|
||||
{
|
||||
#ifdef HAVE_CLOCK_GETTIME
|
||||
struct timespec t;
|
||||
clock_gettime(CLOCK_REALTIME, &t);
|
||||
return (uint64)t.tv_sec * 1000000 + t.tv_nsec / 1000;
|
||||
#else
|
||||
struct timeval t;
|
||||
gettimeofday(&t, NULL);
|
||||
return (uint64)t.tv_sec * 1000000 + t.tv_usec;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Delay by specified number of microseconds (<1 second)
|
||||
* (adapted from SDL_Delay() source; this function is designed to provide
|
||||
* the highest accuracy possible)
|
||||
*/
|
||||
|
||||
#if defined(linux)
|
||||
// Linux select() changes its timeout parameter upon return to contain
|
||||
// the remaining time. Most other unixen leave it unchanged or undefined.
|
||||
#define SELECT_SETS_REMAINING
|
||||
#elif defined(__FreeBSD__) || defined(__sun__)
|
||||
#define USE_NANOSLEEP
|
||||
#elif defined(HAVE_PTHREADS) && defined(sgi)
|
||||
// SGI pthreads has a bug when using pthreads+signals+nanosleep,
|
||||
// so instead of using nanosleep, wait on a CV which is never signalled.
|
||||
#define USE_COND_TIMEDWAIT
|
||||
#endif
|
||||
|
||||
void Delay_usec(uint32 usec)
|
||||
{
|
||||
int was_error;
|
||||
|
||||
#if defined(USE_NANOSLEEP)
|
||||
struct timespec elapsed, tv;
|
||||
#elif defined(USE_COND_TIMEDWAIT)
|
||||
// Use a local mutex and cv, so threads remain independent
|
||||
pthread_cond_t delay_cond = PTHREAD_COND_INITIALIZER;
|
||||
pthread_mutex_t delay_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
struct timespec elapsed;
|
||||
uint64 future;
|
||||
#else
|
||||
struct timeval tv;
|
||||
#ifndef SELECT_SETS_REMAINING
|
||||
uint64 then, now, elapsed;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Set the timeout interval - Linux only needs to do this once
|
||||
#if defined(SELECT_SETS_REMAINING)
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = usec;
|
||||
#elif defined(USE_NANOSLEEP)
|
||||
elapsed.tv_sec = 0;
|
||||
elapsed.tv_nsec = usec * 1000;
|
||||
#elif defined(USE_COND_TIMEDWAIT)
|
||||
future = GetTicks_usec() + usec;
|
||||
elapsed.tv_sec = future / 1000000;
|
||||
elapsed.tv_nsec = (future % 1000000) * 1000;
|
||||
#else
|
||||
then = GetTicks_usec();
|
||||
#endif
|
||||
|
||||
do {
|
||||
errno = 0;
|
||||
#if defined(USE_NANOSLEEP)
|
||||
tv.tv_sec = elapsed.tv_sec;
|
||||
tv.tv_nsec = elapsed.tv_nsec;
|
||||
was_error = nanosleep(&tv, &elapsed);
|
||||
#elif defined(USE_COND_TIMEDWAIT)
|
||||
was_error = pthread_mutex_lock(&delay_mutex);
|
||||
was_error = pthread_cond_timedwait(&delay_cond, &delay_mutex, &elapsed);
|
||||
was_error = pthread_mutex_unlock(&delay_mutex);
|
||||
#else
|
||||
#ifndef SELECT_SETS_REMAINING
|
||||
// Calculate the time interval left (in case of interrupt)
|
||||
now = GetTicks_usec();
|
||||
elapsed = now - then;
|
||||
then = now;
|
||||
if (elapsed >= usec)
|
||||
break;
|
||||
usec -= elapsed;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = usec;
|
||||
#endif
|
||||
was_error = select(0, NULL, NULL, NULL, &tv);
|
||||
#endif
|
||||
} while (was_error && (errno == EINTR));
|
||||
}
|
||||
|
||||
|
||||
#if !EMULATED_68K
|
||||
/*
|
||||
* Virtual 68k interrupt handler
|
||||
|
@ -22,6 +22,8 @@
|
||||
#include "macos_util.h"
|
||||
#include "timer.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#define DEBUG 0
|
||||
#include "debug.h"
|
||||
|
||||
@ -196,3 +198,101 @@ int32 timer_host2mac_time(tm_time_t hosttime)
|
||||
return -t; // Time in negative microseconds
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get current value of microsecond timer
|
||||
*/
|
||||
|
||||
uint64 GetTicks_usec(void)
|
||||
{
|
||||
#ifdef HAVE_CLOCK_GETTIME
|
||||
struct timespec t;
|
||||
clock_gettime(CLOCK_REALTIME, &t);
|
||||
return (uint64)t.tv_sec * 1000000 + t.tv_nsec / 1000;
|
||||
#else
|
||||
struct timeval t;
|
||||
gettimeofday(&t, NULL);
|
||||
return (uint64)t.tv_sec * 1000000 + t.tv_usec;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Delay by specified number of microseconds (<1 second)
|
||||
* (adapted from SDL_Delay() source; this function is designed to provide
|
||||
* the highest accuracy possible)
|
||||
*/
|
||||
|
||||
#if defined(linux)
|
||||
// Linux select() changes its timeout parameter upon return to contain
|
||||
// the remaining time. Most other unixen leave it unchanged or undefined.
|
||||
#define SELECT_SETS_REMAINING
|
||||
#elif defined(__FreeBSD__) || defined(__sun__)
|
||||
#define USE_NANOSLEEP
|
||||
#elif defined(HAVE_PTHREADS) && defined(sgi)
|
||||
// SGI pthreads has a bug when using pthreads+signals+nanosleep,
|
||||
// so instead of using nanosleep, wait on a CV which is never signalled.
|
||||
#define USE_COND_TIMEDWAIT
|
||||
#endif
|
||||
|
||||
void Delay_usec(uint32 usec)
|
||||
{
|
||||
int was_error;
|
||||
|
||||
#if defined(USE_NANOSLEEP)
|
||||
struct timespec elapsed, tv;
|
||||
#elif defined(USE_COND_TIMEDWAIT)
|
||||
// Use a local mutex and cv, so threads remain independent
|
||||
pthread_cond_t delay_cond = PTHREAD_COND_INITIALIZER;
|
||||
pthread_mutex_t delay_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
struct timespec elapsed;
|
||||
uint64 future;
|
||||
#else
|
||||
struct timeval tv;
|
||||
#ifndef SELECT_SETS_REMAINING
|
||||
uint64 then, now, elapsed;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Set the timeout interval - Linux only needs to do this once
|
||||
#if defined(SELECT_SETS_REMAINING)
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = usec;
|
||||
#elif defined(USE_NANOSLEEP)
|
||||
elapsed.tv_sec = 0;
|
||||
elapsed.tv_nsec = usec * 1000;
|
||||
#elif defined(USE_COND_TIMEDWAIT)
|
||||
future = GetTicks_usec() + usec;
|
||||
elapsed.tv_sec = future / 1000000;
|
||||
elapsed.tv_nsec = (future % 1000000) * 1000;
|
||||
#else
|
||||
then = GetTicks_usec();
|
||||
#endif
|
||||
|
||||
do {
|
||||
errno = 0;
|
||||
#if defined(USE_NANOSLEEP)
|
||||
tv.tv_sec = elapsed.tv_sec;
|
||||
tv.tv_nsec = elapsed.tv_nsec;
|
||||
was_error = nanosleep(&tv, &elapsed);
|
||||
#elif defined(USE_COND_TIMEDWAIT)
|
||||
was_error = pthread_mutex_lock(&delay_mutex);
|
||||
was_error = pthread_cond_timedwait(&delay_cond, &delay_mutex, &elapsed);
|
||||
was_error = pthread_mutex_unlock(&delay_mutex);
|
||||
#else
|
||||
#ifndef SELECT_SETS_REMAINING
|
||||
// Calculate the time interval left (in case of interrupt)
|
||||
now = GetTicks_usec();
|
||||
elapsed = now - then;
|
||||
then = now;
|
||||
if (elapsed >= usec)
|
||||
break;
|
||||
usec -= elapsed;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = usec;
|
||||
#endif
|
||||
was_error = select(0, NULL, NULL, NULL, &tv);
|
||||
#endif
|
||||
} while (was_error && (errno == EINTR));
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ enum {
|
||||
// Constants
|
||||
const char KEYCODE_FILE_NAME[] = DATADIR "/keycodes";
|
||||
|
||||
static const int win_eventmask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | ExposureMask | StructureNotifyMask;
|
||||
static const int win_eventmask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | EnterWindowMask | ExposureMask | StructureNotifyMask;
|
||||
static const int dga_eventmask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | StructureNotifyMask;
|
||||
|
||||
|
||||
@ -429,12 +429,17 @@ public:
|
||||
virtual void toggle_mouse_grab(void) {}
|
||||
virtual void mouse_moved(int x, int y) { ADBMouseMoved(x, y); }
|
||||
|
||||
void disable_mouse_accel(void);
|
||||
void restore_mouse_accel(void);
|
||||
|
||||
virtual void grab_mouse(void) {}
|
||||
virtual void ungrab_mouse(void) {}
|
||||
|
||||
public:
|
||||
bool init_ok; // Initialization succeeded (we can't use exceptions because of -fomit-frame-pointer)
|
||||
Window w; // The window we draw into
|
||||
|
||||
int orig_accel_numer, orig_accel_denom, orig_threshold; // Original mouse acceleration
|
||||
};
|
||||
|
||||
class driver_window;
|
||||
@ -478,11 +483,13 @@ driver_base::driver_base()
|
||||
{
|
||||
the_buffer = NULL;
|
||||
the_buffer_copy = NULL;
|
||||
XGetPointerControl(x_display, &orig_accel_numer, &orig_accel_denom, &orig_threshold);
|
||||
}
|
||||
|
||||
driver_base::~driver_base()
|
||||
{
|
||||
ungrab_mouse();
|
||||
restore_mouse_accel();
|
||||
|
||||
if (w) {
|
||||
XUnmapWindow(x_display, w);
|
||||
@ -535,6 +542,18 @@ void driver_base::update_palette(void)
|
||||
XSync(x_display, false);
|
||||
}
|
||||
|
||||
// Disable mouse acceleration
|
||||
void driver_base::disable_mouse_accel(void)
|
||||
{
|
||||
XChangePointerControl(x_display, True, False, 1, 1, 0);
|
||||
}
|
||||
|
||||
// Restore mouse acceleration to original value
|
||||
void driver_base::restore_mouse_accel(void)
|
||||
{
|
||||
XChangePointerControl(x_display, True, True, orig_accel_numer, orig_accel_denom, orig_threshold);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Windowed display driver
|
||||
@ -728,9 +747,9 @@ void driver_window::grab_mouse(void)
|
||||
Delay_usec(100000);
|
||||
}
|
||||
if (result == GrabSuccess) {
|
||||
ADBSetRelMouseMode(mouse_grabbed = true);
|
||||
XStoreName(x_display, w, GetString(STR_WINDOW_TITLE_GRABBED));
|
||||
XSync(x_display, false);
|
||||
ADBSetRelMouseMode(mouse_grabbed = true);
|
||||
disable_mouse_accel();
|
||||
}
|
||||
}
|
||||
|
||||
@ -741,6 +760,7 @@ void driver_window::ungrab_mouse(void)
|
||||
XUngrabPointer(x_display, CurrentTime);
|
||||
XStoreName(x_display, w, GetString(STR_WINDOW_TITLE));
|
||||
ADBSetRelMouseMode(mouse_grabbed = false);
|
||||
restore_mouse_accel();
|
||||
}
|
||||
}
|
||||
|
||||
@ -836,6 +856,7 @@ void driver_dga::suspend(void)
|
||||
#endif
|
||||
XUngrabPointer(x_display, CurrentTime);
|
||||
XUngrabKeyboard(x_display, CurrentTime);
|
||||
restore_mouse_accel();
|
||||
XUnmapWindow(x_display, w);
|
||||
wait_unmapped(w);
|
||||
|
||||
@ -865,6 +886,7 @@ void driver_dga::resume(void)
|
||||
XWarpPointer(x_display, None, rootwin, 0, 0, 0, 0, 0, 0);
|
||||
XGrabKeyboard(x_display, rootwin, True, GrabModeAsync, GrabModeAsync, CurrentTime);
|
||||
XGrabPointer(x_display, rootwin, True, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
|
||||
disable_mouse_accel();
|
||||
#ifdef ENABLE_XF86_DGA
|
||||
XF86DGADirectVideo(x_display, screen, XF86DGADirectGraphics | XF86DGADirectKeyb | XF86DGADirectMouse);
|
||||
XF86DGASetViewPort(x_display, screen, 0, 0);
|
||||
@ -1011,6 +1033,7 @@ driver_fbdev::driver_fbdev(const video_mode &mode)
|
||||
XGrabPointer(x_display, w, True,
|
||||
PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
|
||||
GrabModeAsync, GrabModeAsync, w, None, CurrentTime);
|
||||
disable_mouse_accel();
|
||||
|
||||
// Calculate bytes per row
|
||||
int bytes_per_row = TrivialBytesPerRow(mode.x, mode.depth);
|
||||
@ -1150,6 +1173,7 @@ driver_xf86dga::driver_xf86dga(const video_mode &mode)
|
||||
XWarpPointer(x_display, None, rootwin, 0, 0, 0, 0, 0, 0);
|
||||
XGrabKeyboard(x_display, rootwin, True, GrabModeAsync, GrabModeAsync, CurrentTime);
|
||||
XGrabPointer(x_display, rootwin, True, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
|
||||
disable_mouse_accel();
|
||||
|
||||
int v_width, v_bank, v_size;
|
||||
XF86DGAGetVideo(x_display, screen, (char **)&the_buffer, &v_width, &v_bank, &v_size);
|
||||
@ -1344,12 +1368,18 @@ static bool video_open(const video_mode &mode)
|
||||
--bloss;
|
||||
}
|
||||
|
||||
// Preset palette pixel values for gamma table
|
||||
// Preset palette pixel values for CLUT or gamma table
|
||||
if (color_class == DirectColor) {
|
||||
int num = vis->map_entries;
|
||||
for (int i=0; i<num; i++) {
|
||||
int c = (i * 256) / num;
|
||||
palette[i].pixel = map_rgb(c, c, c);
|
||||
palette[i].flags = DoRed | DoGreen | DoBlue;
|
||||
}
|
||||
} else if (color_class == PseudoColor) {
|
||||
for (int i=0; i<256; i++) {
|
||||
palette[i].pixel = i;
|
||||
palette[i].flags = DoRed | DoGreen | DoBlue;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1360,9 +1390,6 @@ static bool video_open(const video_mode &mode)
|
||||
palette[i].red = c * 0x0101;
|
||||
palette[i].green = c * 0x0101;
|
||||
palette[i].blue = c * 0x0101;
|
||||
if (color_class == PseudoColor)
|
||||
palette[i].pixel = i;
|
||||
palette[i].flags = DoRed | DoGreen | DoBlue;
|
||||
}
|
||||
if (cmap[0] && cmap[1]) {
|
||||
XStoreColors(x_display, cmap[0], palette, num);
|
||||
@ -1371,7 +1398,7 @@ static bool video_open(const video_mode &mode)
|
||||
|
||||
#ifdef ENABLE_VOSF
|
||||
// Load gray ramp to 8->16/32 expand map
|
||||
if (!IsDirectMode(mode) && (color_class == TrueColor || color_class == DirectColor))
|
||||
if (!IsDirectMode(mode) && xdepth > 8)
|
||||
for (int i=0; i<256; i++)
|
||||
ExpandMap[i] = map_rgb(i, i, i);
|
||||
#endif
|
||||
@ -1722,15 +1749,12 @@ void video_set_palette(uint8 *pal, int num_in)
|
||||
p->red = pal[c*3 + 0] * 0x0101;
|
||||
p->green = pal[c*3 + 1] * 0x0101;
|
||||
p->blue = pal[c*3 + 2] * 0x0101;
|
||||
if (color_class == PseudoColor)
|
||||
p->pixel = i;
|
||||
p->flags = DoRed | DoGreen | DoBlue;
|
||||
p++;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_VOSF
|
||||
// Recalculate pixel color expansion map
|
||||
if (!IsDirectMode(VideoMonitor.mode) && (color_class == TrueColor || color_class == DirectColor)) {
|
||||
if (!IsDirectMode(VideoMonitor.mode) && xdepth > 8) {
|
||||
for (int i=0; i<256; i++) {
|
||||
int c = i & (num_in-1); // If there are less than 256 colors, we repeat the first entries (this makes color expansion easier)
|
||||
ExpandMap[i] = map_rgb(pal[c*3+0], pal[c*3+1], pal[c*3+2]);
|
||||
@ -1943,6 +1967,7 @@ static void handle_events(void)
|
||||
XNextEvent(x_display, &event);
|
||||
|
||||
switch (event.type) {
|
||||
|
||||
// Mouse button
|
||||
case ButtonPress: {
|
||||
unsigned int button = event.xbutton.button;
|
||||
@ -1975,6 +2000,12 @@ static void handle_events(void)
|
||||
drv->mouse_moved(event.xmotion.x, event.xmotion.y);
|
||||
break;
|
||||
|
||||
// Mouse entered window
|
||||
case EnterNotify:
|
||||
if (event.xcrossing.mode != NotifyGrab && event.xcrossing.mode != NotifyUngrab)
|
||||
drv->mouse_moved(event.xmotion.x, event.xmotion.y);
|
||||
break;
|
||||
|
||||
// Keyboard
|
||||
case KeyPress: {
|
||||
int code = -1;
|
||||
@ -2311,12 +2342,6 @@ static void video_refresh_dga(void)
|
||||
{
|
||||
// Quit DGA mode if requested
|
||||
possibly_quit_dga_mode();
|
||||
|
||||
// Handle X events
|
||||
handle_events();
|
||||
|
||||
// Handle palette changes
|
||||
handle_palette_changes();
|
||||
}
|
||||
|
||||
#ifdef ENABLE_VOSF
|
||||
@ -2326,12 +2351,6 @@ static void video_refresh_dga_vosf(void)
|
||||
// Quit DGA mode if requested
|
||||
possibly_quit_dga_mode();
|
||||
|
||||
// Handle X events
|
||||
handle_events();
|
||||
|
||||
// Handle palette changes
|
||||
handle_palette_changes();
|
||||
|
||||
// Update display (VOSF variant)
|
||||
static int tick_counter = 0;
|
||||
if (++tick_counter >= frame_skip) {
|
||||
@ -2350,12 +2369,6 @@ static void video_refresh_window_vosf(void)
|
||||
// Ungrab mouse if requested
|
||||
possibly_ungrab_mouse();
|
||||
|
||||
// Handle X events
|
||||
handle_events();
|
||||
|
||||
// Handle palette changes
|
||||
handle_palette_changes();
|
||||
|
||||
// Update display (VOSF variant)
|
||||
static int tick_counter = 0;
|
||||
if (++tick_counter >= frame_skip) {
|
||||
@ -2375,12 +2388,6 @@ static void video_refresh_window_static(void)
|
||||
// Ungrab mouse if requested
|
||||
possibly_ungrab_mouse();
|
||||
|
||||
// Handle X events
|
||||
handle_events();
|
||||
|
||||
// Handle_palette changes
|
||||
handle_palette_changes();
|
||||
|
||||
// Update display (static variant)
|
||||
static int tick_counter = 0;
|
||||
if (++tick_counter >= frame_skip) {
|
||||
@ -2394,12 +2401,6 @@ static void video_refresh_window_dynamic(void)
|
||||
// Ungrab mouse if requested
|
||||
possibly_ungrab_mouse();
|
||||
|
||||
// Handle X events
|
||||
handle_events();
|
||||
|
||||
// Handle_palette changes
|
||||
handle_palette_changes();
|
||||
|
||||
// Update display (dynamic variant)
|
||||
static int tick_counter = 0;
|
||||
tick_counter++;
|
||||
@ -2435,32 +2436,69 @@ static void VideoRefreshInit(void)
|
||||
}
|
||||
}
|
||||
|
||||
// This function is called on non-threaded platforms from a timer interrupt
|
||||
void VideoRefresh(void)
|
||||
{
|
||||
// We need to check redraw_thread_active to inhibit refreshed during
|
||||
// mode changes on non-threaded platforms
|
||||
if (redraw_thread_active)
|
||||
video_refresh();
|
||||
if (!redraw_thread_active)
|
||||
return;
|
||||
|
||||
// Handle X events
|
||||
handle_events();
|
||||
|
||||
// Handle palette changes
|
||||
handle_palette_changes();
|
||||
|
||||
// Update display
|
||||
video_refresh();
|
||||
}
|
||||
|
||||
const int VIDEO_REFRESH_HZ = 60;
|
||||
const int VIDEO_REFRESH_DELAY = 1000000 / VIDEO_REFRESH_HZ;
|
||||
|
||||
#ifdef HAVE_PTHREADS
|
||||
static void *redraw_func(void *arg)
|
||||
{
|
||||
int fd = ConnectionNumber(x_display);
|
||||
|
||||
uint64 start = GetTicks_usec();
|
||||
int64 ticks = 0;
|
||||
uint64 next = GetTicks_usec();
|
||||
uint64 next = GetTicks_usec() + VIDEO_REFRESH_DELAY;
|
||||
|
||||
while (!redraw_thread_cancel) {
|
||||
video_refresh();
|
||||
next += 16667;
|
||||
|
||||
int64 delay = next - GetTicks_usec();
|
||||
if (delay > 0)
|
||||
Delay_usec(delay);
|
||||
else if (delay < -16667)
|
||||
if (delay < -VIDEO_REFRESH_DELAY) {
|
||||
|
||||
// We are lagging far behind, so we reset the delay mechanism
|
||||
next = GetTicks_usec();
|
||||
ticks++;
|
||||
|
||||
} else if (delay <= 0) {
|
||||
|
||||
// Delay expired, refresh display
|
||||
handle_events();
|
||||
handle_palette_changes();
|
||||
video_refresh();
|
||||
next += VIDEO_REFRESH_DELAY;
|
||||
ticks++;
|
||||
|
||||
} else {
|
||||
|
||||
// No display refresh pending, check for X events
|
||||
fd_set readfds;
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(fd, &readfds);
|
||||
struct timeval timeout;
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = delay;
|
||||
if (select(fd+1, &readfds, NULL, NULL, &timeout) > 0)
|
||||
handle_events();
|
||||
}
|
||||
}
|
||||
|
||||
uint64 end = GetTicks_usec();
|
||||
// printf("%Ld ticks in %Ld usec = %Ld ticks/sec\n", ticks, end - start, ticks * 1000000 / (end - start));
|
||||
D(bug("%Ld refreshes in %Ld usec = %f refreshes/sec\n", ticks, end - start, ticks * 1000000.0 / (end - start)));
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
@ -57,7 +57,7 @@ static uint8 mouse_reg_3[2] = {0x63, 0x01}; // Mouse ADB register 3
|
||||
static uint8 key_reg_2[2] = {0xff, 0xff}; // Keyboard ADB register 2
|
||||
static uint8 key_reg_3[2] = {0x62, 0x05}; // Keyboard ADB register 3
|
||||
|
||||
// ADB mouse input state lock (for platforms that use separate input thread)
|
||||
// ADB mouse motion lock (for platforms that use separate input thread)
|
||||
static B2_mutex *mouse_lock;
|
||||
|
||||
|
||||
@ -231,6 +231,8 @@ void ADBMouseMoved(int x, int y)
|
||||
mouse_x = x; mouse_y = y;
|
||||
}
|
||||
B2_unlock_mutex(mouse_lock);
|
||||
SetInterruptFlag(INTFLAG_ADB);
|
||||
TriggerInterrupt();
|
||||
}
|
||||
|
||||
|
||||
@ -240,21 +242,21 @@ void ADBMouseMoved(int x, int y)
|
||||
|
||||
void ADBMouseDown(int button)
|
||||
{
|
||||
B2_lock_mutex(mouse_lock);
|
||||
mouse_button[button] = true;
|
||||
B2_unlock_mutex(mouse_lock);
|
||||
SetInterruptFlag(INTFLAG_ADB);
|
||||
TriggerInterrupt();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* First mouse button released
|
||||
* Mouse button released
|
||||
*/
|
||||
|
||||
void ADBMouseUp(int button)
|
||||
{
|
||||
B2_lock_mutex(mouse_lock);
|
||||
mouse_button[button] = false;
|
||||
B2_unlock_mutex(mouse_lock);
|
||||
SetInterruptFlag(INTFLAG_ADB);
|
||||
TriggerInterrupt();
|
||||
}
|
||||
|
||||
|
||||
@ -264,7 +266,10 @@ void ADBMouseUp(int button)
|
||||
|
||||
void ADBSetRelMouseMode(bool relative)
|
||||
{
|
||||
relative_mouse = relative;
|
||||
if (relative_mouse != relative) {
|
||||
relative_mouse = relative;
|
||||
mouse_x = mouse_y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -280,6 +285,10 @@ void ADBKeyDown(int code)
|
||||
|
||||
// Set key in matrix
|
||||
key_states[code >> 3] |= (1 << (~code & 7));
|
||||
|
||||
// Trigger interrupt
|
||||
SetInterruptFlag(INTFLAG_ADB);
|
||||
TriggerInterrupt();
|
||||
}
|
||||
|
||||
|
||||
@ -295,6 +304,10 @@ void ADBKeyUp(int code)
|
||||
|
||||
// Clear key in matrix
|
||||
key_states[code >> 3] &= ~(1 << (~code & 7));
|
||||
|
||||
// Trigger interrupt
|
||||
SetInterruptFlag(INTFLAG_ADB);
|
||||
TriggerInterrupt();
|
||||
}
|
||||
|
||||
|
||||
|
@ -440,7 +440,6 @@ void EmulOp(uint16 opcode, M68kRegisters *r)
|
||||
if (HasMacStarted()) {
|
||||
|
||||
// Mac has started, execute all 60Hz interrupt functions
|
||||
ADBInterrupt();
|
||||
TimerInterrupt();
|
||||
VideoInterrupt();
|
||||
|
||||
@ -457,7 +456,6 @@ void EmulOp(uint16 opcode, M68kRegisters *r)
|
||||
|
||||
if (InterruptFlags & INTFLAG_1HZ) {
|
||||
ClearInterruptFlag(INTFLAG_1HZ);
|
||||
|
||||
if (HasMacStarted()) {
|
||||
SonyInterrupt();
|
||||
DiskInterrupt();
|
||||
@ -480,11 +478,16 @@ void EmulOp(uint16 opcode, M68kRegisters *r)
|
||||
AudioInterrupt();
|
||||
}
|
||||
|
||||
if (InterruptFlags & INTFLAG_ADB) {
|
||||
ClearInterruptFlag(INTFLAG_ADB);
|
||||
if (HasMacStarted())
|
||||
ADBInterrupt();
|
||||
}
|
||||
|
||||
if (InterruptFlags & INTFLAG_NMI) {
|
||||
ClearInterruptFlag(INTFLAG_NMI);
|
||||
if (HasMacStarted()) {
|
||||
if (HasMacStarted())
|
||||
TriggerNMI();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -66,7 +66,8 @@ enum {
|
||||
INTFLAG_ETHER = 8, // Ethernet driver
|
||||
INTFLAG_AUDIO = 16, // Audio block read
|
||||
INTFLAG_TIMER = 32, // Time Manager
|
||||
INTFLAG_NMI = 64 // NMI
|
||||
INTFLAG_ADB = 64, // ADB
|
||||
INTFLAG_NMI = 128 // NMI
|
||||
};
|
||||
|
||||
extern uint32 InterruptFlags; // Currently pending interrupts
|
||||
|
@ -249,10 +249,8 @@ int16 PrimeTime(uint32 tm, int32 time)
|
||||
|
||||
//!! PrimeTime(0) means continue previous delay
|
||||
// (save wakeup time in RmvTime?)
|
||||
if (time == 0) {
|
||||
printf("FATAL: Unsupported PrimeTime(0)\n");
|
||||
return 0;
|
||||
}
|
||||
if (time == 0)
|
||||
printf("WARNING: Unsupported PrimeTime(0)\n");
|
||||
|
||||
// Yes, calculate wakeup time relative to last scheduled time
|
||||
tm_time_t wakeup;
|
||||
|
@ -23,6 +23,8 @@
|
||||
* SEE ALSO
|
||||
* Inside Macintosh: Devices, chapter 1 "Device Manager"
|
||||
* Designing Cards and Drivers for the Macintosh Family, Second Edition
|
||||
* Designing PCI Cards and Drivers for Power Macintosh Computers
|
||||
* Display Device Driver Guide
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
Loading…
Reference in New Issue
Block a user