Initial import of HatariWii 0.0.5
361
CMakeLists.txt
Normal file
@ -0,0 +1,361 @@
|
||||
|
||||
cmake_minimum_required(VERSION 2.6 FATAL_ERROR)
|
||||
|
||||
if(POLICY CMP0026)
|
||||
# Should be removed if cmake_minimum_required >= 2.8.8
|
||||
cmake_policy(SET CMP0026 OLD)
|
||||
endif(POLICY CMP0026)
|
||||
|
||||
project(Hatari C)
|
||||
|
||||
SET(APP_NAME "Hatari")
|
||||
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
|
||||
|
||||
include(CheckIncludeFiles)
|
||||
include(CheckFunctionExists)
|
||||
include(CheckStructHasMember)
|
||||
include(CheckCCompilerFlag)
|
||||
include(DistClean)
|
||||
|
||||
# Set build type to "Release" if user did not specify any build type yet
|
||||
# Other possible values: Debug, Release, RelWithDebInfo and MinSizeRel
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Release)
|
||||
endif(NOT CMAKE_BUILD_TYPE)
|
||||
|
||||
# set(CMAKE_VERBOSE_MAKEFILE 1)
|
||||
|
||||
# ##########################
|
||||
# Conditional build features
|
||||
# ##########################
|
||||
|
||||
set(ENABLE_SDL2 0
|
||||
CACHE BOOL "Enable building with libSDL2 instead of v1.2")
|
||||
set(ENABLE_DSP_EMU 1
|
||||
CACHE BOOL "Enable DSP 56k emulator for Falcon mode")
|
||||
set(ENABLE_TRACING 1
|
||||
CACHE BOOL "Enable tracing messages for debugging")
|
||||
set(ENABLE_SMALL_MEM 0
|
||||
CACHE BOOL "Enable to use less memory - at the expense of emulation speed")
|
||||
set(ENABLE_WINUAE_CPU 0
|
||||
CACHE BOOL "Enable WinUAE CPU core (experimental!)")
|
||||
|
||||
# Run-time checks with GCC "mudflap" etc features:
|
||||
# - stack protection
|
||||
# - checking of pointer accesses
|
||||
#
|
||||
# Before running CMake, install "mudflap" library development package
|
||||
# (libmudflap0-4.4-dev in Debian Squeeze and libmudflap-devel in Fedora).
|
||||
#
|
||||
# After this you can configure Hatari with Mudflap:
|
||||
# cd build; make clean; cmake -D ENABLE_MUDFLAP:BOOL=1 -D ..
|
||||
# If everything's fine, CMake output should include:
|
||||
# Performing Test MUDFLAP_AVAILABLE - Success"
|
||||
#
|
||||
# After (re-)building Hatari, run it with something like this:
|
||||
# MUDFLAP_OPTIONS="-viol-gdb" src/hatari --sound off --mic off
|
||||
# (sound&mic are disabled because threading doesn't work well with Mudflap)
|
||||
#
|
||||
# For more info:
|
||||
# http://gcc.gnu.org/wiki/Mudflap_Pointer_Debugging
|
||||
#
|
||||
set(CMAKE_REQUIRED_LIBRARIES "mudflap")
|
||||
CHECK_C_COMPILER_FLAG("-fmudflapth" MUDFLAP_AVAILABLE)
|
||||
set(CMAKE_REQUIRED_LIBRARIES "")
|
||||
if(MUDFLAP_AVAILABLE)
|
||||
set(ENABLE_MUDFLAP 0
|
||||
CACHE BOOL "Enable GCC run-time stack/pointer debugging - with huge slowdown")
|
||||
endif(MUDFLAP_AVAILABLE)
|
||||
|
||||
if(APPLE)
|
||||
set(ENABLE_OSX_BUNDLE 1
|
||||
CACHE BOOL "Built Hatari as Mac OS X application bundle")
|
||||
# set(CMAKE_OSX_ARCHITECTURES "i386" CACHE STRING "Target architectures" FORCE)
|
||||
# set(CMAKE_OSX_SYSROOT "/Developer/SDKs/MacOSX10.6.sdk" CACHE STRING "10.6 SDK" FORCE)
|
||||
# set(CMAKE_OSX_DEPLOYMENT_TARGET "10.5" CACHE STRING "Target Min 10.5" FORCE)
|
||||
set(ADDITIONAL_INCLUDES ${FRAMEWORKS})
|
||||
set_source_files_properties(${FRAMEWORKS} PROPERTIES MACOSX_PACKAGE_LOCATION Frameworks)
|
||||
else()
|
||||
set(ENABLE_OSX_BUNDLE 0
|
||||
CACHE BOOL "Built Hatari as Mac OS X application bundle")
|
||||
endif(APPLE)
|
||||
|
||||
# ####################
|
||||
# Check for libraries:
|
||||
# ####################
|
||||
|
||||
if(ENABLE_SDL2)
|
||||
find_package(SDL2 REQUIRED)
|
||||
if(NOT SDL2_FOUND)
|
||||
message(FATAL_ERROR "SDL2 library not found!")
|
||||
endif(NOT SDL2_FOUND)
|
||||
set(SDL_INCLUDE_DIR ${SDL2_INCLUDE_DIR})
|
||||
set(SDL_LIBRARY ${SDL2_LIBRARY})
|
||||
set(SDLMAIN_LIBRARY ${SDL2MAIN_LIBRARY})
|
||||
else(ENABLE_SDL2)
|
||||
find_package(SDL REQUIRED)
|
||||
if(NOT SDL_FOUND)
|
||||
message(FATAL_ERROR "SDL library not found!")
|
||||
endif(NOT SDL_FOUND)
|
||||
endif(ENABLE_SDL2)
|
||||
|
||||
find_package(Math)
|
||||
|
||||
find_package(Readline)
|
||||
if(READLINE_FOUND)
|
||||
set(HAVE_LIBREADLINE 1)
|
||||
endif(READLINE_FOUND)
|
||||
|
||||
find_package(ZLIB)
|
||||
if(ZLIB_FOUND)
|
||||
set(HAVE_LIBZ 1)
|
||||
set(HAVE_ZLIB_H 1)
|
||||
endif(ZLIB_FOUND)
|
||||
|
||||
find_package(PNG)
|
||||
if(PNG_FOUND)
|
||||
set(HAVE_LIBPNG 1)
|
||||
endif(PNG_FOUND)
|
||||
|
||||
if (NOT ENABLE_OSX_BUNDLE)
|
||||
find_package(X11)
|
||||
if(X11_FOUND)
|
||||
set(HAVE_X11 1)
|
||||
endif(X11_FOUND)
|
||||
endif()
|
||||
|
||||
find_package(PortAudio)
|
||||
if(PORTAUDIO_FOUND)
|
||||
set(HAVE_PORTAUDIO 1)
|
||||
endif(PORTAUDIO_FOUND)
|
||||
|
||||
find_package(CapsImage)
|
||||
if(CAPSIMAGE_FOUND)
|
||||
set(HAVE_CAPSIMAGE 1)
|
||||
endif(CAPSIMAGE_FOUND)
|
||||
|
||||
# ################
|
||||
# CPP Definitions:
|
||||
# ################
|
||||
|
||||
# Test for large file support:
|
||||
execute_process(COMMAND getconf LFS_CFLAGS
|
||||
OUTPUT_VARIABLE DETECTED_LFS_CFLAGS
|
||||
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(DETECTED_LFS_CFLAGS)
|
||||
add_definitions(${DETECTED_LFS_CFLAGS})
|
||||
# message(STATUS "Large filesystem flags: ${DETECTED_LFS_CFLAGS}")
|
||||
endif(DETECTED_LFS_CFLAGS)
|
||||
|
||||
# Additional CFLAGS suggested by the SDL library:
|
||||
if(ENABLE_SDL2)
|
||||
add_definitions(-DWITH_SDL2)
|
||||
execute_process(COMMAND pkg-config --cflags-only-other sdl2
|
||||
OUTPUT_VARIABLE DETECTED_SDL_CFLAGS
|
||||
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
else(ENABLE_SDL2)
|
||||
execute_process(COMMAND pkg-config --cflags-only-other sdl
|
||||
OUTPUT_VARIABLE DETECTED_SDL_CFLAGS
|
||||
ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
endif(ENABLE_SDL2)
|
||||
if(DETECTED_SDL_CFLAGS)
|
||||
add_definitions(${DETECTED_SDL_CFLAGS})
|
||||
# message(STATUS "Additional CFLAGS of SDL: ${DETECTED_SDL_CFLAGS}")
|
||||
endif(DETECTED_SDL_CFLAGS)
|
||||
|
||||
if(ENABLE_OSX_BUNDLE)
|
||||
# Use OSX native alert windows
|
||||
add_definitions(-DALERT_HOOKS=1)
|
||||
if(ENABLE_SDL2)
|
||||
# We still want to use our SDLMain.m with SDL2
|
||||
add_definitions(-DSDL_MAIN_NEEDED=1)
|
||||
endif(ENABLE_SDL2)
|
||||
endif(ENABLE_OSX_BUNDLE)
|
||||
|
||||
# ###########################
|
||||
# Check for optional headers:
|
||||
# ###########################
|
||||
|
||||
check_include_files(termios.h HAVE_TERMIOS_H)
|
||||
check_include_files(strings.h HAVE_STRINGS_H)
|
||||
check_include_files(malloc.h HAVE_MALLOC_H)
|
||||
check_include_files(${SDL_INCLUDE_DIR}/SDL_config.h HAVE_SDL_CONFIG_H)
|
||||
check_include_files(sys/times.h HAVE_SYS_TIMES_H)
|
||||
check_include_files("sys/socket.h;sys/un.h" HAVE_UNIX_DOMAIN_SOCKETS)
|
||||
|
||||
# #############################
|
||||
# Check for optional functions:
|
||||
# #############################
|
||||
|
||||
check_function_exists(cfmakeraw HAVE_CFMAKERAW)
|
||||
check_function_exists(setenv HAVE_SETENV)
|
||||
check_function_exists(select HAVE_SELECT)
|
||||
check_function_exists(posix_memalign HAVE_POSIX_MEMALIGN)
|
||||
check_function_exists(memalign HAVE_MEMALIGN)
|
||||
check_function_exists(gettimeofday HAVE_GETTIMEOFDAY)
|
||||
check_function_exists(nanosleep HAVE_NANOSLEEP)
|
||||
check_function_exists(alphasort HAVE_ALPHASORT)
|
||||
check_function_exists(scandir HAVE_SCANDIR)
|
||||
check_function_exists(statvfs HAVE_STATVFS)
|
||||
check_function_exists(fseeko HAVE_FSEEKO)
|
||||
check_function_exists(ftello HAVE_FTELLO)
|
||||
check_function_exists(flock HAVE_FLOCK)
|
||||
check_function_exists(strlcpy HAVE_LIBC_STRLCPY)
|
||||
check_struct_has_member("struct dirent" d_type dirent.h HAVE_DIRENT_D_TYPE)
|
||||
|
||||
# #############
|
||||
# Other CFLAGS:
|
||||
# #############
|
||||
|
||||
# GCC pointer debugging, huge run-time slowdown
|
||||
if(ENABLE_MUDFLAP)
|
||||
# SDL mixer threads so have to use threaded mudflap version
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -fstack-protector-all -fmudflapth")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fmudflapth -lmudflap")
|
||||
endif(ENABLE_MUDFLAP)
|
||||
|
||||
# Warning flags:
|
||||
if(CMAKE_COMPILER_IS_GNUCC)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wcast-qual -Wbad-function-cast -Wpointer-arith")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wmissing-prototypes -Wstrict-prototypes")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wwrite-strings -Wsign-compare")
|
||||
#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra -Wno-unused-parameter -Wno-empty-body")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wformat-security")
|
||||
#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wshadow -D_FORTIFY_SOURCE=2 -Werror")
|
||||
endif(CMAKE_COMPILER_IS_GNUCC)
|
||||
|
||||
# Building Hatari w/o optimization is no fun...
|
||||
IF (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(CMAKE_C_FLAGS "-O ${CMAKE_C_FLAGS}")
|
||||
ENDIF (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
|
||||
# ####################
|
||||
# Paths configuration:
|
||||
# ####################
|
||||
|
||||
if(NOT BINDIR)
|
||||
set(BINDIR bin)
|
||||
endif()
|
||||
|
||||
if(NOT DATADIR)
|
||||
set(DATADIR share/hatari)
|
||||
endif()
|
||||
|
||||
if(NOT BIN2DATADIR)
|
||||
if(WIN32)
|
||||
set(BIN2DATADIR "."
|
||||
CACHE STRING "Relative path from bindir to datadir")
|
||||
elseif(ENABLE_OSX_BUNDLE)
|
||||
set(BIN2DATADIR "../Resources"
|
||||
CACHE STRING "Relative path from bindir to datadir")
|
||||
else()
|
||||
set(BIN2DATADIR "../share/hatari"
|
||||
CACHE STRING "Relative path from bindir to datadir")
|
||||
endif(WIN32)
|
||||
mark_as_advanced(BIN2DATADIR)
|
||||
endif()
|
||||
|
||||
if(NOT MANDIR)
|
||||
set(MANDIR share/man/man1)
|
||||
endif()
|
||||
|
||||
if(NOT DOCDIR)
|
||||
set(DOCDIR share/doc/hatari)
|
||||
endif()
|
||||
|
||||
if(NOT ETCDIR)
|
||||
if(WIN32)
|
||||
set(ETCDIR .)
|
||||
else()
|
||||
set(ETCDIR /etc)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT ICONDIR)
|
||||
set(ICONDIR share/icons/hicolor)
|
||||
endif()
|
||||
|
||||
if(ENABLE_OSX_BUNDLE)
|
||||
# put the config files in the app's bundle
|
||||
add_definitions(-DCONFDIR=\"../Resources\")
|
||||
else()
|
||||
add_definitions(-DCONFDIR=\"${ETCDIR}\")
|
||||
endif()
|
||||
|
||||
# #########################################
|
||||
# Create config.h and recurse into subdirs:
|
||||
# #########################################
|
||||
|
||||
configure_file(${CMAKE_SOURCE_DIR}/cmake/config-cmake.h
|
||||
${CMAKE_BINARY_DIR}/config.h)
|
||||
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(doc)
|
||||
add_subdirectory(tools)
|
||||
|
||||
include(FindPythonInterp)
|
||||
if(PYTHONINTERP_FOUND)
|
||||
add_subdirectory(python-ui)
|
||||
endif(PYTHONINTERP_FOUND)
|
||||
|
||||
if(UNIX AND NOT ENABLE_OSX_BUNDLE)
|
||||
add_subdirectory(share)
|
||||
endif()
|
||||
|
||||
add_custom_target(uninstall
|
||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_SOURCE_DIR}/cmake/Uninstall.cmake)
|
||||
|
||||
|
||||
# ###################################################################
|
||||
# Print a summary of the optional libraries with a short explanation:
|
||||
# ###################################################################
|
||||
|
||||
message( "
|
||||
Libraries summary :
|
||||
-------------------
|
||||
")
|
||||
|
||||
if(SDL2_FOUND)
|
||||
message(" - sdl :\tusing SDL2 v${SDL2_VERSION_STRING}")
|
||||
else()
|
||||
if(SDL_VERSION_STRING)
|
||||
message(" - sdl :\tusing SDL v${SDL_VERSION_STRING}")
|
||||
else()
|
||||
message(" - sdl :\tusing SDL1")
|
||||
endif(SDL_VERSION_STRING)
|
||||
endif(SDL2_FOUND)
|
||||
|
||||
if(READLINE_FOUND)
|
||||
message( " - readline :\tfound, enables history/completion in the debugger" )
|
||||
else()
|
||||
message( " - readline :\tnot found, install it to enable debugger history/completion" )
|
||||
endif(READLINE_FOUND)
|
||||
|
||||
if(ZLIB_FOUND)
|
||||
message( " - zlib :\tfound, allows to use zip/gz files directly" )
|
||||
else()
|
||||
message( " - zlib :\tnot found, install it to use zip/gz files" )
|
||||
endif(ZLIB_FOUND)
|
||||
|
||||
if(PNG_FOUND)
|
||||
message( " - png :\tfound, allows to compress screenshot/avi files using png" )
|
||||
else()
|
||||
message( " - png :\tnot found, install it to compress screenshot/avi files using png" )
|
||||
endif(PNG_FOUND)
|
||||
|
||||
if(PORTAUDIO_FOUND)
|
||||
message( " - portaudio :\tfound, enables the microphone input in Falcon mode" )
|
||||
else()
|
||||
message( " - portaudio :\tnot found, install it to enable the Falcon microphone input" )
|
||||
endif(PORTAUDIO_FOUND)
|
||||
|
||||
if(CAPSIMAGE_FOUND)
|
||||
message( " - capsimage :\tv${CAPSIMAGE_VERSION} found, allow to use .IPF, .RAW and .CTR disk images" )
|
||||
else()
|
||||
message( " - capsimage :\tv${CAPSIMAGE_VERSION} not found, install it to use .IPF, .RAW and .CTR disk images" )
|
||||
endif(CAPSIMAGE_FOUND)
|
||||
|
||||
message( "" )
|
||||
|
||||
|
6
Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
all:
|
||||
cd src; $(MAKE) -f Makefile.wii
|
||||
clean:
|
||||
cd src; $(MAKE) -f Makefile.wii clean
|
||||
run:
|
||||
cd src; wiiload hatari.dol
|
132
Makefile-default.cnf
Executable file
@ -0,0 +1,132 @@
|
||||
# Makefile configuration for Hatari.
|
||||
#
|
||||
# Use of '?=' for assignment allows overriding the given value with
|
||||
# an environment variable, like this:
|
||||
# HOSTCC=my-hostcc make
|
||||
# or:
|
||||
# export HOSTCC=my-hostcc
|
||||
# make
|
||||
#
|
||||
# Following variables can be overridden like that:
|
||||
# CPPFLAGS, LDFLAGS, LIBS, HOSTCC, DATADIR, CONFDIR, BINDIR, MANDIR, DOCDIR
|
||||
#
|
||||
# GNU make itself supports overriding CC like this:
|
||||
# make CC=my-cc
|
||||
|
||||
# Set the C compiler (e.g. gcc)
|
||||
CC = gcc
|
||||
|
||||
OPTFLAGS = -O2
|
||||
|
||||
# Architecture specific settings
|
||||
#
|
||||
# Omap2/ARMv6:
|
||||
# OPTFLAGS += -mfpu=vfp -mfloat-abi=softfp -march=armv6 -finline-limit=64
|
||||
#
|
||||
# Wii/Gekko:
|
||||
# OPTFLAGS = -MMD -MP -MF -O3 -mrvl -mcpu=750 -meabi -mhard-float
|
||||
# CPPFLAGS = -DGEKKO -I$(DEVKITPRO)/libogc/include -I$(DEVKITPRO)/libogc/include/sdl
|
||||
# LDFLAGS = -L$(DEVKITPRO)/libogc/lib/wii -Wl,-Map,hatari.map
|
||||
# LIBS = -lz -lfat -lwiiuse -lbte -lasnd -logc -lm
|
||||
|
||||
# What warnings to use
|
||||
WARNFLAGS = -Wmissing-prototypes -Wstrict-prototypes -Wsign-compare \
|
||||
-Wbad-function-cast -Wcast-qual -Wpointer-arith \
|
||||
-Wall -Wwrite-strings # -Wshadow -Wcast-align -Werror
|
||||
|
||||
|
||||
ifneq ($(MUDFLAP),)
|
||||
# Run-time checks with GCC "mudflap" etc:
|
||||
# - stack protection
|
||||
# - checking of pointer accesses (AFAIK works only on x86)
|
||||
#
|
||||
# Before build, install "libmudflap<version>-<gcc-version>-dev"
|
||||
# package (libmudflap0-4.3-dev in Debian Lenny).
|
||||
#
|
||||
# To build, use:
|
||||
# make clean; make MUDFLAP=1
|
||||
#
|
||||
# To run, use something like (disable sound as it can break things):
|
||||
# MUDFLAP_OPTIONS="-viol-gdb" ./hatari --sound off
|
||||
#
|
||||
# For more info, see (for now, works properly only for x86 gcc):
|
||||
# http://gcc.gnu.org/wiki/Mudflap_Pointer_Debugging
|
||||
#
|
||||
RUNCHECKS = -fstack-protector-all -fmudflapth #-fmudflapir
|
||||
LDRUNCHECKS = -fmudflapth -lmudflap
|
||||
endif
|
||||
|
||||
|
||||
# Set flags passed to the compiler (e.g. optimization flags)
|
||||
CFLAGS := -g $(WARNFLAGS) $(OPTFLAGS) $(RUNCHECKS)
|
||||
|
||||
# Set flags passed to the preprocessor (e.g. -I<include dir>)
|
||||
CPPFLAGS ?=
|
||||
|
||||
# Additional libraries and linker flags:
|
||||
LIBS ?= -lz -lm # -lreadline
|
||||
LDFLAGS ?= $(LDRUNCHECKS)
|
||||
|
||||
# Ranlib - for generating an index of an archive
|
||||
RANLIB = ranlib
|
||||
|
||||
|
||||
# The native C compiler.
|
||||
# This is normally the same as $(CC) unless you are using a cross compiler.
|
||||
HOSTCC ?= $(CC)
|
||||
|
||||
# Native C compiler flags:
|
||||
HOSTCFLAGS = -g -O -Wall
|
||||
|
||||
# Native linker flags:
|
||||
HOSTLDFLAGS =
|
||||
|
||||
|
||||
# SDL-Library configuration (compiler flags and linker options) - you normally
|
||||
# don't have to change this if you have correctly installed the SDL library!
|
||||
SDL_CFLAGS := $(shell sdl-config --cflags)
|
||||
SDL_LIBS := $(shell sdl-config --libs)
|
||||
|
||||
# libpng configuration (for PNG format screenshots)
|
||||
PNG_LIBS := $(shell pkg-config --silence-errors --libs libpng)
|
||||
ifneq ($(PNG_LIBS),)
|
||||
PNG_CFLAGS := -DHAVE_LIBPNG=1 $(shell pkg-config --cflags libpng)
|
||||
endif
|
||||
|
||||
# X11 configuration (for SDL window embedding)
|
||||
X11_LIBS := $(shell pkg-config --silence-errors --libs x11)
|
||||
ifneq ($(X11_LIBS),)
|
||||
X11_CFLAGS := -DHAVE_X11=1 $(shell pkg-config --cflags x11)
|
||||
endif
|
||||
|
||||
# PORTAUDIO configuration (to support Falcon microphone)
|
||||
PORTAUDIO_LIBS := $(shell pkg-config --silence-errors --libs portaudio-2.0)
|
||||
ifneq ($(PORTAUDIO_LIBS),)
|
||||
PORTAUDIO_CFLAGS := -DHAVE_PORTAUDIO=1 $(shell pkg-config --cflags portaudio-2.0)
|
||||
endif
|
||||
|
||||
# Here you can define the default data directory for Hatari.
|
||||
# The emulator looks there for the default TOS image etc.
|
||||
# For example you can use the local directory with "." or if you want
|
||||
# a system-wide installation, use something like "/usr/share/hatari".
|
||||
DATADIR ?= .
|
||||
|
||||
# In this folder, Hatari searches the global configuration file.
|
||||
# /etc or /usr/local/etc is a good place for this.
|
||||
CONFDIR ?= /etc
|
||||
|
||||
# The executable will be installed in BINDIR
|
||||
#BINDIR ?= /usr/local/bin
|
||||
|
||||
# The man-page will be install in MANDIR
|
||||
#MANDIR ?= /usr/local/share/man/man1
|
||||
|
||||
# All other documentation will be installed in DOCDIR
|
||||
#DOCDIR ?= /usr/local/share/doc/hatari
|
||||
|
||||
# Program used for "make install"
|
||||
#INSTALL = install -c
|
||||
#INSTALL_PROGRAM = $(INSTALL) -s -m 755
|
||||
#INSTALL_SCRIPT = $(INSTALL) -m 755
|
||||
#INSTALL_DATA = $(INSTALL) -m 644
|
||||
|
62
Makefile-wii.cnf
Executable file
@ -0,0 +1,62 @@
|
||||
# Makefile configuration for Hatari.
|
||||
#
|
||||
# Use of '?=' for assignment allows overriding the given value with
|
||||
# an environment variable, e.g. like this "make CC=my-gcc"
|
||||
#
|
||||
# Following variables can be overridden:
|
||||
# CC, CPPFLAGS, LDFLAGS, HOSTCC, DATADIR, CONFDIR, BINDIR
|
||||
|
||||
# Set the C compiler (e.g. gcc)
|
||||
CC = powerpc-eabi-gcc
|
||||
|
||||
# Include directories
|
||||
INCLUDE = -I$(DEVKITPRO)/libogc/include -I$(DEVKITPRO)/libogc/include/SDL
|
||||
|
||||
DEFINES = -DHAVE_DIRENT_D_TYPE
|
||||
|
||||
# Architecture specific optimizations
|
||||
#
|
||||
# Omap2/ARMv6:
|
||||
# OPTFLAGS += -mfpu=vfp -mfloat-abi=softfp -march=armv6 -finline-limit=64
|
||||
|
||||
OPTFLAGS = -MMD -MP -MF -flto -O2 -DGEKKO -mrvl -mcpu=750 -meabi -mhard-float
|
||||
|
||||
# What warnings to use
|
||||
WARNFLAGS = -Wsign-compare \
|
||||
-Wbad-function-cast -Wcast-qual -Wpointer-arith \
|
||||
-Wall -Wwrite-strings # -Wshadow -Wcast-align -Werror
|
||||
|
||||
# Set flags passed to the compiler (e.g. optimization flags)
|
||||
CFLAGS := -g $(WARNFLAGS) $(INCLUDE) $(OPTFLAGS) $(DEFINES)
|
||||
|
||||
# Set flags passed to the preprocessor (e.g. -I<include dir>)
|
||||
CPPFLAGS ?=
|
||||
|
||||
# Additional libraries and linker flags:
|
||||
LIBS = -lz # -lreadline
|
||||
LDFLAGS ?= -g -DGEKKO -mrvl -mcpu=750 -meabi -mhard-float -Wl,-Map,hatari.map
|
||||
|
||||
# Ranlib - for generating an index of an archive
|
||||
RANLIB = ranlib
|
||||
|
||||
# The native C compiler.
|
||||
# This is normaly the same as $(CC) unless you are using a cross compiler.
|
||||
HOSTCC ?= gcc
|
||||
|
||||
# Native C compiler flags:
|
||||
HOSTCFLAGS = -g -O -Wall
|
||||
|
||||
# Native linker flags:
|
||||
HOSTLDFLAGS =
|
||||
|
||||
# SDL-Library configuration (compiler flags and linker options) - you normally
|
||||
# don't have to change this if you have correctly installed the SDL library!
|
||||
#SDL_CFLAGS := -I$(DEVKITPRO)/libogc/include
|
||||
SDL_LIBS := -L$(DEVKITPRO)/libogc/lib/wii -lSDL_ttf -lSDL_image -lsmpeg -lSDL -lpng -ljpeg -lvorbisidec -lfat -lwiiuse -lbte -lz -logc -lm -lwiikeyboard
|
||||
|
||||
# Here you can define the default data directory for Hatari.
|
||||
# The emulator looks there for the default TOS image etc.
|
||||
# For example you can use the local directory with "." or if you want
|
||||
# a system-wide installation, use something like "/usr/share/hatari".
|
||||
#BIN2DATADIR ?= /apps/hatari
|
||||
|
80
Visual.Studio/VisualStudioFix.c
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Hatari - Fix for compliation using Visual Studio 6
|
||||
*
|
||||
* This file is distributed under the GNU General Public License, version 2
|
||||
* or at your option any later version. Read the file gpl.txt for details.
|
||||
*/
|
||||
|
||||
#if defined(_VCWIN_)
|
||||
#pragma comment(lib, ".\\SDL\\lib\\sdl.lib") // sdl.lib
|
||||
#pragma comment(lib, ".\\zlib\\win32\\zlib1.lib") // zlib1.lib
|
||||
#endif
|
||||
|
||||
#if defined(_VCWIN_)
|
||||
#include <tchar.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
|
||||
#include "log.h"
|
||||
|
||||
extern FILE *TraceFile;
|
||||
|
||||
#if defined(_VCWIN_)
|
||||
#ifndef _INC_HATARI_TRACE
|
||||
#define _INC_HATARI_TRACE
|
||||
|
||||
#if ENABLE_TRACING
|
||||
void LOG_TRACE(int level, const char* format, ...)
|
||||
{
|
||||
va_list x;
|
||||
va_start(x,format);
|
||||
if ( HatariTraceFlags & level ) _vftprintf(TraceFile,format, x);
|
||||
va_end (x);
|
||||
};
|
||||
#else /* ENABLE_TRACING */
|
||||
void LOG_TRACE(int level, ...)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* ENABLE_TRACING */
|
||||
|
||||
void LOG_TRACE_PRINT(char* strFirstString, ...)
|
||||
{
|
||||
va_list x;
|
||||
va_start(x,strFirstString);
|
||||
_vftprintf(TraceFile,strFirstString, x);
|
||||
va_end (x);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
|
||||
// Windows Header Files:
|
||||
#include <windows.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
extern int SDL_main(int argc, char *argv[]);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
return SDL_main(argc,argv);
|
||||
}
|
||||
|
||||
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
||||
LPSTR lpCmdLine, int nCmdShow)
|
||||
{
|
||||
return SDL_main(1,&lpCmdLine);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
135
Visual.Studio/VisualStudioFix.h
Normal file
@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Hatari - Fix for compliation using Visual Studio 6
|
||||
*
|
||||
* This file is distributed under the GNU General Public License, version 2
|
||||
* or at your option any later version. Read the file gpl.txt for details.
|
||||
*
|
||||
* This file tells Visual Studio to ignore a number of relatively minor "warnings" that have found their
|
||||
* way into the HAtari source. None of the "warnings" will hamper the running or compliation or HAtari
|
||||
* but it is possible not addressing them may make it difficult for other developers to be sure of the
|
||||
* intentions of the original coders against whos code these warnings are raised.
|
||||
* As long as the original coder was aware of the warnings and of the implicit result of adding no
|
||||
* explicit casts to remove them then things are good.
|
||||
*
|
||||
* 2009 Vaughan Kaufman
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(_VCWIN_) // Stop Visual Studio complaining about all the implicit type conversions (wish we would make them explict guys/girls)
|
||||
#pragma warning (disable:4244) // conversion with potential data loss
|
||||
#pragma warning (disable:4761) // integral size mismatch in argument
|
||||
#pragma warning (disable:4146) // unary minus operator applied to unsigned type
|
||||
#pragma warning (disable:4018) // signed / unsigned mismatch
|
||||
#pragma warning (disable:4102) // ignore unused label warning
|
||||
#pragma warning (disable:4049) // (this one is silly, its not important) compiler limit, end of line numbering
|
||||
#pragma warning (disable:4800) // Performance Warning on Conversion of bool to int
|
||||
#pragma warning (disable:4805) // warning C4805: '|=' : unsafe mix of type 'int' and type 'bool' in operation
|
||||
#endif
|
||||
|
||||
/*
|
||||
* KVK - Fix for compliation using Visual Studio 6
|
||||
*
|
||||
* Microsoft have created multiple versions of the standard C calls, a specific version exists for each type of string encoding
|
||||
* format (in this case UNICODE (Wide) and ANSI (Ascii) versions. This has lead to there being versions with a A or a W after
|
||||
* the name to signify the encoding. There are other additional reasons why they have these different versions (something to
|
||||
* do with the change from BSTR to string class passing I think, anyone?). The upshot is, we need to add a _ to the beginning of
|
||||
* some of the function names for HAtari to compile..
|
||||
*
|
||||
* 2009 Vaughan Kaufman
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(_VCWIN_)
|
||||
#define STATIC_INLINE static __inline
|
||||
#define GLOB_ONLYDIR 0
|
||||
|
||||
#include <io.h>
|
||||
#include <direct.h>
|
||||
#include <stdbool.h>
|
||||
#include <tchar.h>
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
#define stat _stat
|
||||
#define S_IRUSR _S_IREAD
|
||||
#define S_IWUSR _S_IWRITE
|
||||
#define S_ISDIR(val) (_S_IFDIR & val)
|
||||
#define S_IFDIR _S_IFDIR
|
||||
|
||||
#define strncasecmp _strnicmp
|
||||
#ifndef strcasecmp
|
||||
#define strcasecmp _stricmp
|
||||
#endif
|
||||
#define chdrive _chdrive
|
||||
#define strdup _strdup
|
||||
#define getcwd _getcwd
|
||||
#define fileno _fileno
|
||||
#define unlink _unlink
|
||||
#define access _access
|
||||
#ifndef mkdir
|
||||
#define mkdir(name,mode) _mkdir(name)
|
||||
#endif
|
||||
#define rmdir _rmdir
|
||||
#define chmod _chmod
|
||||
#define itoa _itoa
|
||||
#define stricmp _stricmp
|
||||
#define snprintf _snprintf
|
||||
#define vsnprintf _vsnprintf
|
||||
|
||||
#define __attribute__(x) /* x */
|
||||
|
||||
// For new UI
|
||||
|
||||
typedef unsigned short mode_t;
|
||||
|
||||
#ifndef _NEW_UI_TYPES
|
||||
#define _NEW_UI_TYPES
|
||||
typedef signed __int8 int8;
|
||||
typedef unsigned __int8 uint8;
|
||||
typedef signed __int16 int16;
|
||||
typedef unsigned __int16 uint16;
|
||||
typedef signed __int32 int32;
|
||||
typedef unsigned __int32 uint32;
|
||||
typedef signed __int64 int64;
|
||||
typedef unsigned __int64 uint64;
|
||||
typedef void* memptr;
|
||||
#endif
|
||||
|
||||
typedef signed __int8 int8_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef signed __int16 int16_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef signed __int32 int32_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef signed __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
|
||||
#ifndef __inline__
|
||||
#define __inline__ __inline
|
||||
#endif
|
||||
|
||||
/* The variable-types used in the CPU core: */
|
||||
typedef uint8_t uae_u8;
|
||||
typedef int8_t uae_s8;
|
||||
|
||||
typedef uint16_t uae_u16;
|
||||
typedef int16_t uae_s16;
|
||||
|
||||
typedef uint32_t uae_u32;
|
||||
typedef int32_t uae_s32;
|
||||
|
||||
typedef uae_u32 uaecptr;
|
||||
|
||||
extern void LOG_TRACE(int level, ...);
|
||||
extern void LOG_TRACE_PRINT(char* strFirstString, ...);
|
||||
|
||||
#ifdef JOY_BUTTON1
|
||||
#undef JOY_BUTTON1
|
||||
#endif
|
||||
#ifdef JOY_BUTTON2
|
||||
#undef JOY_BUTTON2
|
||||
#endif
|
||||
|
||||
extern void Win_OpenCon(void);
|
||||
|
||||
#endif
|
27
cmake/DistClean.cmake
Normal file
@ -0,0 +1,27 @@
|
||||
#
|
||||
# "distclean" target for removing the generated files from CMake
|
||||
#
|
||||
|
||||
if(UNIX)
|
||||
add_custom_target(distclean COMMENT "Cleaning up for distribution")
|
||||
# Clean up Hatari specific files:
|
||||
foreach(CLEAN_FILE config.h install_manifest.txt src/hatari
|
||||
src/cpu/build68k src/cpu/cpudefs.c src/cpu/cpuemu_*.c
|
||||
src/cpu/cpustbl.c src/cpu/cputbl.h src/cpu/gencpu
|
||||
src/uae-cpu/build68k src/uae-cpu/gencpu
|
||||
src/uae-cpu/cpudefs.c src/uae-cpu/cpuemu.c
|
||||
src/uae-cpu/cpustbl.c src/uae-cpu/cputbl.h
|
||||
tools/hmsa/hmsa tools/debugger/gst2ascii
|
||||
python-ui/conftypes.py)
|
||||
add_custom_command(TARGET distclean POST_BUILD
|
||||
COMMAND rm -f ${CLEAN_FILE}
|
||||
DEPENDS clean)
|
||||
endforeach(CLEAN_FILE)
|
||||
# Clean up files that can appear at multiple places:
|
||||
foreach(CLEAN_FILE CMakeFiles CMakeCache.txt '*.a' '*.1.gz'
|
||||
cmake_install.cmake Makefile)
|
||||
add_custom_command(TARGET distclean POST_BUILD
|
||||
COMMAND find . -depth -name ${CLEAN_FILE} | xargs rm -rf
|
||||
DEPENDS clean)
|
||||
endforeach(CLEAN_FILE)
|
||||
endif(UNIX)
|
31
cmake/FindCapsImage.cmake
Normal file
@ -0,0 +1,31 @@
|
||||
|
||||
IF (CAPSIMAGE_INCLUDE_DIR)
|
||||
# Already in cache, be silent
|
||||
SET(CAPSIMAGE_FIND_QUIETLY TRUE)
|
||||
ENDIF (CAPSIMAGE_INCLUDE_DIR)
|
||||
|
||||
|
||||
# Choose the library version to use : 4 or 5
|
||||
SET(CAPSIMAGE_VERSION 4)
|
||||
|
||||
|
||||
if(CAPSIMAGE_VERSION STREQUAL 4)
|
||||
SET(CAPSIMAGE_DIR caps)
|
||||
FIND_PATH(CAPSIMAGE_INCLUDE_DIR ${CAPSIMAGE_DIR}/capsimage.h)
|
||||
else()
|
||||
SET(CAPSIMAGE_DIR caps5)
|
||||
FIND_PATH(CAPSIMAGE_INCLUDE_DIR ${CAPSIMAGE_DIR}/CapsAPI.h)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
FIND_LIBRARY(CAPSIMAGE_LIBRARY NAMES capsimg PATH_SUFFIXES ${CAPSIMAGE_DIR} )
|
||||
else()
|
||||
FIND_LIBRARY(CAPSIMAGE_LIBRARY NAMES capsimage PATH_SUFFIXES ${CAPSIMAGE_DIR} )
|
||||
endif(WIN32)
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(CAPSIMAGE DEFAULT_MSG
|
||||
CAPSIMAGE_LIBRARY CAPSIMAGE_INCLUDE_DIR)
|
||||
|
||||
|
||||
MARK_AS_ADVANCED(CAPSIMAGE_LIBRARY CAPSIMAGE_INCLUDE_DIR)
|
15
cmake/FindMath.cmake
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
if(MATH_INCLUDE_DIR)
|
||||
# Already in cache, be silent
|
||||
set(MATH_FIND_QUIETLY TRUE)
|
||||
endif(MATH_INCLUDE_DIR)
|
||||
|
||||
find_path(MATH_INCLUDE_DIR math.h)
|
||||
|
||||
find_library(MATH_LIBRARY NAMES m)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(MATH DEFAULT_MSG
|
||||
MATH_LIBRARY MATH_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(MATH_LIBRARY MATH_INCLUDE_DIR)
|
35
cmake/FindPortAudio.cmake
Normal file
@ -0,0 +1,35 @@
|
||||
#
|
||||
# Find the native PORTAUDIO (version 2) includes and library
|
||||
#
|
||||
# PORTAUDIO_INCLUDE_DIR - where to find portaudio.h, etc.
|
||||
# PORTAUDIO_LIBRARY - List of libraries when using portaudio.
|
||||
# PORTAUDIO_FOUND - True if portaudio found.
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
include(CheckFunctionExists)
|
||||
|
||||
if(PORTAUDIO_INCLUDE_DIR)
|
||||
# Already in cache, be silent
|
||||
set(PORTAUDIO_FIND_QUIETLY TRUE)
|
||||
endif(PORTAUDIO_INCLUDE_DIR)
|
||||
|
||||
find_path(PORTAUDIO_INCLUDE_DIR portaudio.h)
|
||||
|
||||
find_library(PORTAUDIO_LIBRARY NAMES portaudio)
|
||||
|
||||
# handle the QUIETLY and REQUIRED arguments and set PORTAUDIO_FOUND to TRUE if
|
||||
# all listed variables are TRUE
|
||||
find_package_handle_standard_args(PORTAUDIO DEFAULT_MSG
|
||||
PORTAUDIO_LIBRARY PORTAUDIO_INCLUDE_DIR)
|
||||
|
||||
# Check if it's really a portaudio2 installation...
|
||||
if(PORTAUDIO_FOUND)
|
||||
set(CMAKE_REQUIRED_LIBRARIES ${PORTAUDIO_LIBRARY})
|
||||
check_function_exists(Pa_GetDefaultInputDevice HAVE_PA_GETDEFAULTINPUTDEVICE)
|
||||
if (NOT HAVE_PA_GETDEFAULTINPUTDEVICE)
|
||||
unset (PORTAUDIO_FOUND)
|
||||
endif(NOT HAVE_PA_GETDEFAULTINPUTDEVICE)
|
||||
set(CMAKE_REQUIRED_LIBRARIES "")
|
||||
endif(PORTAUDIO_FOUND)
|
||||
|
||||
mark_as_advanced(PORTAUDIO_LIBRARY PORTAUDIO_INCLUDE_DIR)
|
53
cmake/FindReadline.cmake
Normal file
@ -0,0 +1,53 @@
|
||||
|
||||
IF (READLINE_INCLUDE_DIR)
|
||||
# Already in cache, be silent
|
||||
SET(READLINE_FIND_QUIETLY TRUE)
|
||||
ENDIF (READLINE_INCLUDE_DIR)
|
||||
|
||||
FIND_PATH(READLINE_INCLUDE_DIR readline.h PATH_SUFFIXES readline)
|
||||
|
||||
FIND_LIBRARY(READLINE_LIBRARY NAMES readline)
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(READLINE DEFAULT_MSG
|
||||
READLINE_LIBRARY READLINE_INCLUDE_DIR)
|
||||
|
||||
MARK_AS_ADVANCED(READLINE_LIBRARY READLINE_INCLUDE_DIR)
|
||||
|
||||
if(READLINE_FOUND)
|
||||
set(CMAKE_REQUIRED_LIBRARIES "readline")
|
||||
check_function_exists(rl_filename_completion_function
|
||||
HAVE_RL_COMPLETION_FUNCTION)
|
||||
# If linking did not work, we might have to link
|
||||
# explicitely against libtermcap or libncurses
|
||||
if(NOT HAVE_RL_COMPLETION_FUNCTION)
|
||||
unset(READLINE_FOUND)
|
||||
find_package(Termcap)
|
||||
if(TERMCAP_FOUND)
|
||||
set(CMAKE_REQUIRED_LIBRARIES "readline" "termcap")
|
||||
check_function_exists(rl_filename_completion_function
|
||||
HAVE_RL_COMPLETION_FUNCTION_TERMCAP)
|
||||
endif(TERMCAP_FOUND)
|
||||
if(HAVE_RL_COMPLETION_FUNCTION_TERMCAP)
|
||||
set(READLINE_LIBRARY ${READLINE_LIBRARY} ${TERMCAP_LIBRARY})
|
||||
set(READLINE_FOUND TRUE)
|
||||
else(HAVE_RL_COMPLETION_FUNCTION_TERMCAP)
|
||||
find_package(Curses)
|
||||
if(CURSES_FOUND)
|
||||
if(CURSES_NCURSES_LIBRARY)
|
||||
set(CMAKE_REQUIRED_LIBRARIES "readline" "ncurses")
|
||||
else()
|
||||
set(CMAKE_REQUIRED_LIBRARIES "readline" "curses")
|
||||
endif()
|
||||
check_function_exists(rl_filename_completion_function
|
||||
HAVE_RL_COMPLETION_FUNCTION_CURSES)
|
||||
if(HAVE_RL_COMPLETION_FUNCTION_CURSES)
|
||||
set(READLINE_LIBRARY
|
||||
${READLINE_LIBRARY} ${CURSES_LIBRARIES})
|
||||
set(READLINE_FOUND TRUE)
|
||||
endif(HAVE_RL_COMPLETION_FUNCTION_CURSES)
|
||||
endif(CURSES_FOUND)
|
||||
endif(HAVE_RL_COMPLETION_FUNCTION_TERMCAP)
|
||||
endif(NOT HAVE_RL_COMPLETION_FUNCTION)
|
||||
set(CMAKE_REQUIRED_LIBRARIES "")
|
||||
endif(READLINE_FOUND)
|
177
cmake/FindSDL2.cmake
Normal file
@ -0,0 +1,177 @@
|
||||
# Locate SDL2 library
|
||||
# This module defines
|
||||
# SDL2_LIBRARY, the name of the library to link against
|
||||
# SDL2_FOUND, if false, do not try to link to SDL2
|
||||
# SDL2_INCLUDE_DIR, where to find SDL.h
|
||||
#
|
||||
# This module responds to the the flag:
|
||||
# SDL2_BUILDING_LIBRARY
|
||||
# If this is defined, then no SDL2main will be linked in because
|
||||
# only applications need main().
|
||||
# Otherwise, it is assumed you are building an application and this
|
||||
# module will attempt to locate and set the the proper link flags
|
||||
# as part of the returned SDL2_LIBRARY variable.
|
||||
#
|
||||
# Don't forget to include SDLmain.h and SDLmain.m your project for the
|
||||
# OS X framework based version. (Other versions link to -lSDL2main which
|
||||
# this module will try to find on your behalf.) Also for OS X, this
|
||||
# module will automatically add the -framework Cocoa on your behalf.
|
||||
#
|
||||
#
|
||||
# Additional Note: If you see an empty SDL2_LIBRARY_TEMP in your configuration
|
||||
# and no SDL2_LIBRARY, it means CMake did not find your SDL2 library
|
||||
# (SDL2.dll, libsdl2.so, SDL2.framework, etc).
|
||||
# Set SDL2_LIBRARY_TEMP to point to your SDL2 library, and configure again.
|
||||
# Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value
|
||||
# as appropriate. These values are used to generate the final SDL2_LIBRARY
|
||||
# variable, but when these values are unset, SDL2_LIBRARY does not get created.
|
||||
#
|
||||
#
|
||||
# $SDL2DIR is an environment variable that would
|
||||
# correspond to the ./configure --prefix=$SDL2DIR
|
||||
# used in building SDL2.
|
||||
# l.e.galup 9-20-02
|
||||
#
|
||||
# Modified by Eric Wing.
|
||||
# Added code to assist with automated building by using environmental variables
|
||||
# and providing a more controlled/consistent search behavior.
|
||||
# Added new modifications to recognize OS X frameworks and
|
||||
# additional Unix paths (FreeBSD, etc).
|
||||
# Also corrected the header search path to follow "proper" SDL guidelines.
|
||||
# Added a search for SDL2main which is needed by some platforms.
|
||||
# Added a search for threads which is needed by some platforms.
|
||||
# Added needed compile switches for MinGW.
|
||||
#
|
||||
# On OSX, this will prefer the Framework version (if found) over others.
|
||||
# People will have to manually change the cache values of
|
||||
# SDL2_LIBRARY to override this selection or set the CMake environment
|
||||
# CMAKE_INCLUDE_PATH to modify the search paths.
|
||||
#
|
||||
# Note that the header path has changed from SDL2/SDL.h to just SDL.h
|
||||
# This needed to change because "proper" SDL convention
|
||||
# is #include "SDL.h", not <SDL2/SDL.h>. This is done for portability
|
||||
# reasons because not all systems place things in SDL2/ (see FreeBSD).
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2003-2009 Kitware, Inc.
|
||||
#
|
||||
# Distributed under the OSI-approved BSD License (the "License");
|
||||
# see http://www.cmake.org/cmake/project/license.html for details.
|
||||
#
|
||||
# This software is distributed WITHOUT ANY WARRANTY; without even the
|
||||
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# See the License for more information.
|
||||
#=============================================================================
|
||||
|
||||
SET(SDL2_SEARCH_PATHS
|
||||
~/Library/Frameworks
|
||||
/Library/Frameworks
|
||||
/usr/local
|
||||
/usr
|
||||
/sw # Fink
|
||||
/opt/local # DarwinPorts
|
||||
/opt/csw # Blastwave
|
||||
/opt
|
||||
)
|
||||
|
||||
FIND_PATH(SDL2_INCLUDE_DIR SDL_scancode.h
|
||||
HINTS
|
||||
$ENV{SDL2DIR}
|
||||
PATH_SUFFIXES include/SDL2 include
|
||||
PATHS ${SDL2_SEARCH_PATHS}
|
||||
)
|
||||
|
||||
FIND_LIBRARY(SDL2_LIBRARY_TEMP
|
||||
NAMES SDL2
|
||||
HINTS
|
||||
$ENV{SDL2DIR}
|
||||
PATH_SUFFIXES lib64 lib
|
||||
PATHS ${SDL2_SEARCH_PATHS}
|
||||
)
|
||||
|
||||
IF(NOT SDL2_BUILDING_LIBRARY)
|
||||
IF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
|
||||
# Non-OS X framework versions expect you to also dynamically link to
|
||||
# SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms
|
||||
# seem to provide SDL2main for compatibility even though they don't
|
||||
# necessarily need it.
|
||||
FIND_LIBRARY(SDL2MAIN_LIBRARY
|
||||
NAMES SDL2main
|
||||
HINTS
|
||||
$ENV{SDL2DIR}
|
||||
PATH_SUFFIXES lib64 lib
|
||||
PATHS ${SDL2_SEARCH_PATHS}
|
||||
)
|
||||
ENDIF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
|
||||
ENDIF(NOT SDL2_BUILDING_LIBRARY)
|
||||
|
||||
# SDL2 may require threads on your system.
|
||||
# The Apple build may not need an explicit flag because one of the
|
||||
# frameworks may already provide it.
|
||||
# But for non-OSX systems, I will use the CMake Threads package.
|
||||
IF(NOT APPLE)
|
||||
FIND_PACKAGE(Threads)
|
||||
ENDIF(NOT APPLE)
|
||||
|
||||
# MinGW needs an additional library, mwindows
|
||||
# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -lmwindows
|
||||
# (Actually on second look, I think it only needs one of the m* libraries.)
|
||||
IF(MINGW)
|
||||
SET(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW")
|
||||
ENDIF(MINGW)
|
||||
|
||||
IF(SDL2_LIBRARY_TEMP)
|
||||
# For SDL2main
|
||||
IF(NOT SDL2_BUILDING_LIBRARY)
|
||||
IF(SDL2MAIN_LIBRARY)
|
||||
SET(SDL2_LIBRARY_TEMP ${SDL2MAIN_LIBRARY} ${SDL2_LIBRARY_TEMP})
|
||||
ENDIF(SDL2MAIN_LIBRARY)
|
||||
ENDIF(NOT SDL2_BUILDING_LIBRARY)
|
||||
|
||||
# For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa.
|
||||
# CMake doesn't display the -framework Cocoa string in the UI even
|
||||
# though it actually is there if I modify a pre-used variable.
|
||||
# I think it has something to do with the CACHE STRING.
|
||||
# So I use a temporary variable until the end so I can set the
|
||||
# "real" variable in one-shot.
|
||||
IF(APPLE)
|
||||
SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} "-framework Cocoa")
|
||||
ENDIF(APPLE)
|
||||
|
||||
# For threads, as mentioned Apple doesn't need this.
|
||||
# In fact, there seems to be a problem if I used the Threads package
|
||||
# and try using this line, so I'm just skipping it entirely for OS X.
|
||||
IF(NOT APPLE)
|
||||
SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT})
|
||||
ENDIF(NOT APPLE)
|
||||
|
||||
# For MinGW library
|
||||
IF(MINGW)
|
||||
SET(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP})
|
||||
ENDIF(MINGW)
|
||||
|
||||
# Set the final string here so the GUI reflects the final state.
|
||||
SET(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL2 Library can be found")
|
||||
# Set the temp variable to INTERNAL so it is not seen in the CMake GUI
|
||||
SET(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "")
|
||||
ENDIF(SDL2_LIBRARY_TEMP)
|
||||
|
||||
if(SDL2_INCLUDE_DIR AND EXISTS "${SDL2_INCLUDE_DIR}/SDL_version.h")
|
||||
file(STRINGS "${SDL2_INCLUDE_DIR}/SDL_version.h" SDL2_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_MAJOR_VERSION[ \t]+[0-9]+$")
|
||||
file(STRINGS "${SDL2_INCLUDE_DIR}/SDL_version.h" SDL2_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_MINOR_VERSION[ \t]+[0-9]+$")
|
||||
file(STRINGS "${SDL2_INCLUDE_DIR}/SDL_version.h" SDL2_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_PATCHLEVEL[ \t]+[0-9]+$")
|
||||
string(REGEX REPLACE "^#define[ \t]+SDL_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_MAJOR "${SDL2_VERSION_MAJOR_LINE}")
|
||||
string(REGEX REPLACE "^#define[ \t]+SDL_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_MINOR "${SDL2_VERSION_MINOR_LINE}")
|
||||
string(REGEX REPLACE "^#define[ \t]+SDL_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_PATCH "${SDL2_VERSION_PATCH_LINE}")
|
||||
set(SDL2_VERSION_STRING ${SDL2_VERSION_MAJOR}.${SDL2_VERSION_MINOR}.${SDL2_VERSION_PATCH})
|
||||
unset(SDL2_VERSION_MAJOR_LINE)
|
||||
unset(SDL2_VERSION_MINOR_LINE)
|
||||
unset(SDL2_VERSION_PATCH_LINE)
|
||||
unset(SDL2_VERSION_MAJOR)
|
||||
unset(SDL2_VERSION_MINOR)
|
||||
unset(SDL2_VERSION_PATCH)
|
||||
endif()
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR)
|
14
cmake/FindTermcap.cmake
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
if(TERMCAP_INCLUDE_DIR)
|
||||
# Already in cache, be silent
|
||||
set(TERMCAP_FIND_QUIETLY TRUE)
|
||||
endif(TERMCAP_INCLUDE_DIR)
|
||||
|
||||
find_path(TERMCAP_INCLUDE_DIR termcap.h)
|
||||
find_library(TERMCAP_LIBRARY NAMES termcap)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(TERMCAP DEFAULT_MSG
|
||||
TERMCAP_LIBRARY TERMCAP_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(TERMCAP_LIBRARY TERMCAP_INCLUDE_DIR)
|
48
cmake/Toolchain-mingw32-win64_32.cmake
Normal file
@ -0,0 +1,48 @@
|
||||
# This Toolchain file is used to cross compile the Windows 32 bit
|
||||
# version of Hatari under linux using mingw32
|
||||
# use : cmake -DCMAKE_TOOLCHAIN_FILE=Toolchain-mingw32-win64_32.cmake
|
||||
|
||||
|
||||
# mingw32 versions of the different tools
|
||||
# (change these depending on your system settings)
|
||||
set (MINGW_EXE_PREFIX "i686-w64-mingw32")
|
||||
set (MINGW_ROOT_PATH "mingw")
|
||||
|
||||
|
||||
#-- Changes should not be required below this point
|
||||
|
||||
# The name of the target operating system
|
||||
SET(CMAKE_SYSTEM_NAME Windows)
|
||||
|
||||
# Use the value provided to set mingw's tools
|
||||
SET(CMAKE_C_COMPILER ${MINGW_EXE_PREFIX}-gcc)
|
||||
SET(CMAKE_CXX_COMPILER ${MINGW_EXE_PREFIX}-g++)
|
||||
SET(CMAKE_RC_COMPILER ${MINGW_EXE_PREFIX}-windres)
|
||||
|
||||
# Base directory for the target environment
|
||||
# We use the output from '-print-sysroot'
|
||||
EXECUTE_PROCESS(
|
||||
COMMAND ${CMAKE_C_COMPILER} -print-sysroot
|
||||
OUTPUT_VARIABLE CMAKE_FIND_ROOT_PATH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
# bin/, include/, lib/ and share/ are often in "mingw/"
|
||||
# You might need to adjust the path for your system
|
||||
SET(CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH}/${MINGW_ROOT_PATH})
|
||||
|
||||
# Make the path absolute, a relative path could confuse some systems
|
||||
get_filename_component ( CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH} ABSOLUTE )
|
||||
|
||||
#message ( "MINGW_ROOT_PATH ${MINGW_ROOT_PATH} MINGW_EXE_PREFIX ${MINGW_EXE_PREFIX} CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH}" )
|
||||
|
||||
# FindSDL.cmake doesn't search correctly in CMAKE_FIND_ROOT_PATH
|
||||
# so we force SDLDIR here
|
||||
set ( ENV{SDLDIR} ${CMAKE_FIND_ROOT_PATH}/include/SDL )
|
||||
|
||||
# Adjust the default behaviour of the FIND_XXX() commands:
|
||||
# search headers and libraries in the target environment, search
|
||||
# programs in the host environment
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
|
48
cmake/Toolchain-mingw32-win64_64.cmake
Normal file
@ -0,0 +1,48 @@
|
||||
# This Toolchain file is used to cross compile the Windows 64 bit
|
||||
# version of Hatari under linux using mingw32
|
||||
# use : cmake -DCMAKE_TOOLCHAIN_FILE=Toolchain-mingw32-win64_64.cmake
|
||||
|
||||
|
||||
# mingw32 versions of the different tools
|
||||
# (change these depending on your system settings)
|
||||
set (MINGW_EXE_PREFIX "x86_64-w64-mingw32")
|
||||
set (MINGW_ROOT_PATH "mingw")
|
||||
|
||||
|
||||
#-- Changes should not be required below this point
|
||||
|
||||
# The name of the target operating system
|
||||
SET(CMAKE_SYSTEM_NAME Windows)
|
||||
|
||||
# Use the value provided to set mingw's tools
|
||||
SET(CMAKE_C_COMPILER ${MINGW_EXE_PREFIX}-gcc)
|
||||
SET(CMAKE_CXX_COMPILER ${MINGW_EXE_PREFIX}-g++)
|
||||
SET(CMAKE_RC_COMPILER ${MINGW_EXE_PREFIX}-windres)
|
||||
|
||||
# Base directory for the target environment
|
||||
# We use the output from '-print-sysroot'
|
||||
EXECUTE_PROCESS(
|
||||
COMMAND ${CMAKE_C_COMPILER} -print-sysroot
|
||||
OUTPUT_VARIABLE CMAKE_FIND_ROOT_PATH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
# bin/, include/, lib/ and share/ are often in "mingw/"
|
||||
# You might need to adjust the path for your system
|
||||
SET(CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH}/${MINGW_ROOT_PATH})
|
||||
|
||||
# Make the path absolute, a relative path could confuse some systems
|
||||
get_filename_component ( CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH} ABSOLUTE )
|
||||
|
||||
#message ( "MINGW_ROOT_PATH ${MINGW_ROOT_PATH} MINGW_EXE_PREFIX ${MINGW_EXE_PREFIX} CMAKE_FIND_ROOT_PATH ${CMAKE_FIND_ROOT_PATH}" )
|
||||
|
||||
# FindSDL.cmake doesn't search correctly in CMAKE_FIND_ROOT_PATH
|
||||
# so we force SDLDIR here
|
||||
set ( ENV{SDLDIR} ${CMAKE_FIND_ROOT_PATH}/include/SDL )
|
||||
|
||||
# Adjust the default behaviour of the FIND_XXX() commands:
|
||||
# search headers and libraries in the target environment, search
|
||||
# programs in the host environment
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
|
32
cmake/Uninstall.cmake
Normal file
@ -0,0 +1,32 @@
|
||||
#
|
||||
# "uninstall" target for reverting "make install"
|
||||
#
|
||||
|
||||
# cmake_policy(SET CMP0007 NEW)
|
||||
|
||||
if (NOT EXISTS "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt")
|
||||
message(FATAL_ERROR "Cannot find install manifest: \"${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt\"")
|
||||
endif()
|
||||
|
||||
file(READ "${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt" files)
|
||||
string(REGEX REPLACE "\n" ";" files "${files}")
|
||||
# list(REVERSE files)
|
||||
foreach (file ${files})
|
||||
message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"")
|
||||
if (EXISTS "$ENV{DESTDIR}${file}")
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E remove "$ENV{DESTDIR}${file}"
|
||||
OUTPUT_VARIABLE rm_out
|
||||
RESULT_VARIABLE rm_retval
|
||||
)
|
||||
if(NOT ${rm_retval} EQUAL 0)
|
||||
message(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"")
|
||||
endif (NOT ${rm_retval} EQUAL 0)
|
||||
else (EXISTS "$ENV{DESTDIR}${file}")
|
||||
message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.")
|
||||
endif (EXISTS "$ENV{DESTDIR}${file}")
|
||||
endforeach(file)
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E remove ${CMAKE_CURRENT_BINARY_DIR}/install_manifest.txt
|
||||
)
|
101
cmake/config-cmake.h
Normal file
@ -0,0 +1,101 @@
|
||||
/* CMake config.h for Hatari */
|
||||
|
||||
/* Define if you have a PNG compatible library */
|
||||
#cmakedefine HAVE_LIBPNG 1
|
||||
|
||||
/* Define if you have a readline compatible library */
|
||||
#cmakedefine HAVE_LIBREADLINE 1
|
||||
|
||||
/* Define if you have the PortAudio library */
|
||||
#cmakedefine HAVE_PORTAUDIO 1
|
||||
|
||||
/* Define if you have the capsimage library */
|
||||
#cmakedefine HAVE_CAPSIMAGE 1
|
||||
#cmakedefine CAPSIMAGE_VERSION @CAPSIMAGE_VERSION@
|
||||
|
||||
/* Define if you have a X11 environment */
|
||||
#cmakedefine HAVE_X11 1
|
||||
|
||||
/* Define to 1 if you have the `z' library (-lz). */
|
||||
#cmakedefine HAVE_LIBZ 1
|
||||
|
||||
/* Define to 1 if you have the <zlib.h> header file. */
|
||||
#cmakedefine HAVE_ZLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the <termios.h> header file. */
|
||||
#cmakedefine HAVE_TERMIOS_H 1
|
||||
|
||||
/* Define to 1 if you have the <glob.h> header file. */
|
||||
#cmakedefine HAVE_GLOB_H 1
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
#cmakedefine HAVE_STRINGS_H 1
|
||||
|
||||
/* Define to 1 if you have the <SDL_config.h> header file. */
|
||||
#cmakedefine HAVE_SDL_CONFIG_H 1
|
||||
|
||||
/* Define to 1 if you have the <sys/times.h> header file. */
|
||||
#cmakedefine HAVE_SYS_TIMES_H 1
|
||||
|
||||
/* Define to 1 if you have the `cfmakeraw' function. */
|
||||
#cmakedefine HAVE_CFMAKERAW 1
|
||||
|
||||
/* Define to 1 if you have the 'setenv' function. */
|
||||
#cmakedefine HAVE_SETENV 1
|
||||
|
||||
/* Define to 1 if you have the `select' function. */
|
||||
#cmakedefine HAVE_SELECT 1
|
||||
|
||||
/* Define to 1 if you have unix domain sockets */
|
||||
#cmakedefine HAVE_UNIX_DOMAIN_SOCKETS 1
|
||||
|
||||
/* Define to 1 if you have the 'posix_memalign' function. */
|
||||
#cmakedefine HAVE_POSIX_MEMALIGN 1
|
||||
|
||||
/* Define to 1 if you have the 'memalign' function. */
|
||||
#cmakedefine HAVE_MEMALIGN 1
|
||||
|
||||
/* Define to 1 if you have the 'gettimeofday' function. */
|
||||
#cmakedefine HAVE_GETTIMEOFDAY 1
|
||||
|
||||
/* Define to 1 if you have the 'nanosleep' function. */
|
||||
#cmakedefine HAVE_NANOSLEEP 1
|
||||
|
||||
/* Define to 1 if you have the 'alphasort' function. */
|
||||
#cmakedefine HAVE_ALPHASORT 1
|
||||
|
||||
/* Define to 1 if you have the 'scandir' function. */
|
||||
#cmakedefine HAVE_SCANDIR 1
|
||||
|
||||
/* Define to 1 if you have the 'statvfs' function. */
|
||||
#cmakedefine HAVE_STATVFS 1
|
||||
|
||||
/* Define to 1 if you have the 'fseeko' function. */
|
||||
#cmakedefine HAVE_FSEEKO 1
|
||||
|
||||
/* Define to 1 if you have the 'ftello' function. */
|
||||
#cmakedefine HAVE_FTELLO 1
|
||||
|
||||
/* Define to 1 if you have the 'flock' function. */
|
||||
#cmakedefine HAVE_FLOCK 1
|
||||
|
||||
/* Define to 1 if you have the 'strlcpy' function. */
|
||||
#cmakedefine HAVE_LIBC_STRLCPY 1
|
||||
|
||||
/* Define to 1 if you have the 'd_type' member in the 'dirent' struct */
|
||||
#cmakedefine HAVE_DIRENT_D_TYPE 1
|
||||
|
||||
/* Relative path from bindir to datadir */
|
||||
#define BIN2DATADIR "@BIN2DATADIR@"
|
||||
|
||||
/* Define to 1 to enable DSP 56k emulation for Falcon mode */
|
||||
#cmakedefine ENABLE_DSP_EMU 1
|
||||
|
||||
/* Define to 1 to enable WINUAE cpu */
|
||||
#cmakedefine ENABLE_WINUAE_CPU 1
|
||||
|
||||
/* Define to 1 to use less memory - at the expense of emulation speed */
|
||||
#cmakedefine ENABLE_SMALL_MEM 1
|
||||
|
||||
/* Define to 1 to enable trace logs - undefine to slightly increase speed */
|
||||
#cmakedefine ENABLE_TRACING 1
|
86
config.h
Normal file
@ -0,0 +1,86 @@
|
||||
/* Default config.h for Hatari */
|
||||
|
||||
/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'. */
|
||||
//#define HAVE_DIRENT_H 1
|
||||
|
||||
/* Define if you have a readline compatible library */
|
||||
#undef HAVE_LIBREADLINE
|
||||
|
||||
/* Define to 1 if you have the `z' library (-lz). */
|
||||
#define HAVE_LIBZ 1
|
||||
|
||||
/* Define to 1 if you have the <zlib.h> header file. */
|
||||
#define HAVE_ZLIB_H 1
|
||||
|
||||
/* Define to 1 if you have the <termios.h> header file. */
|
||||
//#if defined(WIN32)
|
||||
# undef HAVE_TERMIOS_H
|
||||
//#else
|
||||
//# define HAVE_TERMIOS_H 1
|
||||
//#endif
|
||||
|
||||
/* Define to 1 if you have the <glob.h> header file. */
|
||||
//#if defined(WIN32)
|
||||
# undef HAVE_GLOB_H
|
||||
//#else
|
||||
//# define HAVE_GLOB_H 1
|
||||
//#endif
|
||||
|
||||
/* Define to 1 if you have the <strings.h> header file. */
|
||||
//#if defined(__CEGCC__)
|
||||
# undef HAVE_STRINGS_H
|
||||
//#else
|
||||
//# define HAVE_STRINGS_H 1
|
||||
//#endif
|
||||
|
||||
/* Define to 1 if you have the `strcasecmp' function. */
|
||||
#define HAVE_STRCASECMP 1
|
||||
|
||||
/* Define to 1 if you have the `strncasecmp' function. */
|
||||
#define HAVE_STRNCASECMP 1
|
||||
|
||||
/* Define to 1 if you have the `cfmakeraw' function. */
|
||||
# undef HAVE_CFMAKERAW
|
||||
|
||||
/* Define to 1 if you have the 'setenv' function. */
|
||||
//#if defined(WIN32) || (defined(__sun) && defined(__SVR4))
|
||||
# undef HAVE_SETENV
|
||||
//#else
|
||||
//# define HAVE_SETENV 1
|
||||
//#endif
|
||||
|
||||
/* Define to 1 if you have unix domain sockets */
|
||||
//#if defined(WIN32) || defined(__CEGCC__)
|
||||
# undef HAVE_UNIX_DOMAIN_SOCKETS
|
||||
//#else
|
||||
//# define HAVE_UNIX_DOMAIN_SOCKETS 1
|
||||
//#endif
|
||||
|
||||
/* Relative path from bindir to datadir */
|
||||
#define BIN2DATADIR "/apps/hatari"
|
||||
|
||||
/* configuration file path */
|
||||
#define CONFDIR "/apps/hatari"
|
||||
|
||||
/* games folder */
|
||||
#define DATADIR "/hatari"
|
||||
|
||||
/* Define to 1 to use less memory - at the expense of emulation speed */
|
||||
//#if defined(__CEGCC__)
|
||||
#define ENABLE_SMALL_MEM 1
|
||||
//#else
|
||||
//# undef ENABLE_SMALL_MEM
|
||||
//#endif
|
||||
|
||||
|
||||
//#define ENABLE_WINUAE_CPU 1
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME "hatari"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "hatari CVS"
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "CVS"
|
||||
|
115
configure
vendored
Executable file
@ -0,0 +1,115 @@
|
||||
#!/bin/sh
|
||||
|
||||
# NOTE: this is a simple script wrapper around the cmake command line tools,
|
||||
# for those used to the autotools configure script conventions
|
||||
|
||||
if ! which cmake > /dev/null; then
|
||||
echo "ERROR: You need the 'cmake' program to configure the Hatari build process."
|
||||
echo "Please install 'cmake' first, then try again."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_help()
|
||||
{
|
||||
echo "This is a simple configure script wrapper around cmake build system."
|
||||
echo "Parameters are:"
|
||||
echo " --prefix=<path> Set the install prefix to path"
|
||||
echo " --enable-debug Enable debug (non-optimized) build"
|
||||
echo " --enable-small-mem Use less memory - at the expense of emulation speed"
|
||||
echo " --disable-dsp Disable DSP emulation for Falcon mode."
|
||||
echo " --disable-tracing Disable tracing messages for debugging"
|
||||
echo " --enable-winuae-cpu Enable WinUAE CPU core (experimental!)"
|
||||
echo " --disable-osx-bundle Disable application bundling on Mac OS X"
|
||||
echo " --enable-sdl2 Compile with libsdl 2.0 instead of 1.2"
|
||||
echo " --cross-compile-win64_32 Build the 32 bit Windows version under linux using mingw-w64"
|
||||
echo " --cross-compile-win64_64 Build the 64 bit Windows version under linux using mingw-w64"
|
||||
echo
|
||||
echo "Please run cmake directly for full control over the build."
|
||||
echo
|
||||
}
|
||||
|
||||
cmake_args=""
|
||||
build_type="Release"
|
||||
|
||||
while [ $# -gt 0 ]
|
||||
do
|
||||
preq=${1%=*} # get part before =
|
||||
case $preq
|
||||
in
|
||||
--help)
|
||||
print_help
|
||||
exit 0
|
||||
;;
|
||||
--prefix)
|
||||
prefix=${1##*=} # get part after =
|
||||
cmake_args="$cmake_args -DCMAKE_INSTALL_PREFIX:PATH=$prefix"
|
||||
;;
|
||||
--enable-debug)
|
||||
build_type="Debug"
|
||||
cmake_args="$cmake_args -DCMAKE_BUILD_TYPE:STRING=Debug"
|
||||
;;
|
||||
--disable-debug)
|
||||
build_type="Release"
|
||||
cmake_args="$cmake_args -DCMAKE_BUILD_TYPE:STRING=Release"
|
||||
;;
|
||||
--enable-dsp)
|
||||
cmake_args="$cmake_args -DENABLE_DSP_EMU:BOOL=1"
|
||||
;;
|
||||
--disable-dsp)
|
||||
cmake_args="$cmake_args -DENABLE_DSP_EMU:BOOL=0"
|
||||
;;
|
||||
--enable-tracing)
|
||||
cmake_args="$cmake_args -DENABLE_TRACING:BOOL=1"
|
||||
;;
|
||||
--disable-tracing)
|
||||
cmake_args="$cmake_args -DENABLE_TRACING:BOOL=0"
|
||||
;;
|
||||
--enable-small-mem)
|
||||
cmake_args="$cmake_args -DENABLE_SMALL_MEM:BOOL=1"
|
||||
;;
|
||||
--disable-small-mem)
|
||||
cmake_args="$cmake_args -DENABLE_SMALL_MEM:BOOL=0"
|
||||
;;
|
||||
--enable-winuae-cpu)
|
||||
cmake_args="$cmake_args -DENABLE_WINUAE_CPU:BOOL=1"
|
||||
;;
|
||||
--disable-winuae-cpu)
|
||||
cmake_args="$cmake_args -DENABLE_WINUAE_CPU:BOOL=0"
|
||||
;;
|
||||
--enable-osx-bundle)
|
||||
cmake_args="$cmake_args -DENABLE_OSX_BUNDLE:BOOL=1"
|
||||
;;
|
||||
--disable-osx-bundle)
|
||||
cmake_args="$cmake_args -DENABLE_OSX_BUNDLE:BOOL=0"
|
||||
;;
|
||||
--enable-sdl2)
|
||||
cmake_args="$cmake_args -DENABLE_SDL2:BOOL=1"
|
||||
;;
|
||||
--disable-sdl2)
|
||||
cmake_args="$cmake_args -DENABLE_SDL2:BOOL=0"
|
||||
;;
|
||||
--cross-compile-win64_32)
|
||||
cmake_args="$cmake_args -DCMAKE_TOOLCHAIN_FILE=cmake/Toolchain-mingw32-win64_32.cmake"
|
||||
;;
|
||||
--cross-compile-win64_64)
|
||||
cmake_args="$cmake_args -DCMAKE_TOOLCHAIN_FILE=cmake/Toolchain-mingw32-win64_64.cmake"
|
||||
;;
|
||||
*)
|
||||
echo "Invalid argument: $preq"
|
||||
echo "Run $0 --help for a list of valid parameters."
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
shift 1
|
||||
done
|
||||
|
||||
# remove previous cmake's cache
|
||||
rm -f `dirname $0`/CMakeCache.txt
|
||||
rm -rf `dirname $0`/CMakeFiles/
|
||||
|
||||
cmake `dirname $0` $cmake_args || exit 1
|
||||
|
||||
echo
|
||||
echo "Now you must type: make; make install"
|
||||
echo "to actually build and install the software"
|
||||
echo
|
18
doc/CMakeLists.txt
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
INSTALL(FILES authors.txt emutos.txt keymap-sample.txt memory-usage.txt
|
||||
midi-linux.txt release-notes.txt todo.txt
|
||||
DESTINATION ${DOCDIR})
|
||||
|
||||
INSTALL(FILES compatibility.html manual.html
|
||||
DESTINATION ${DOCDIR})
|
||||
|
||||
INSTALL(DIRECTORY images
|
||||
DESTINATION ${DOCDIR})
|
||||
|
||||
# if(UNIX)
|
||||
add_custom_target(manpages ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/hatari.1.gz)
|
||||
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/hatari.1.gz
|
||||
COMMAND gzip -c -9 ${CMAKE_CURRENT_SOURCE_DIR}/hatari.1 > ${CMAKE_CURRENT_BINARY_DIR}/hatari.1.gz
|
||||
DEPENDS hatari.1)
|
||||
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hatari.1.gz DESTINATION ${MANDIR})
|
||||
# endif(UNIX)
|
198
doc/authors.txt
Normal file
@ -0,0 +1,198 @@
|
||||
|
||||
Active Hatari developers:
|
||||
-------------------------
|
||||
|
||||
- Nicolas Pomarede <npomarede at corp.free.fr> : Project admin,
|
||||
improving CPU, video, sound, IKBD and floppy emulation.
|
||||
|
||||
- Thomas Huth <huth at tuxfamily.org> : Project initiator and
|
||||
admin, currently more or less in hibernation mode.
|
||||
|
||||
- Eero Tamminen <oak at helsinkinet fi> : Speed improvements & code
|
||||
cleanup, small parts of the STE emulation, Python CLI, UI & TOS
|
||||
tester + Hatari window embedding & remote control API, pause & auto
|
||||
frameskip support, statusbar & overlay led, conditional breakpoints
|
||||
and other debugger features, GEMDOS HD emulation improvements, PNG
|
||||
saving.
|
||||
|
||||
- Laurent Sallafranque: Many fixes and speedups to DSP emulation,
|
||||
DSP debugging support, crossbar emulation, falcon microphone
|
||||
emulation, STE LMC1992/microwire emulation, Videl emulation.
|
||||
|
||||
|
||||
Contributors:
|
||||
-------------
|
||||
|
||||
Following people contributed code or patches to this projects and/or
|
||||
helped to find bugs in Hatari (listed in random order - and if someone
|
||||
is missing here, please remind me!):
|
||||
|
||||
- Jean-Baptiste Berlioz <tobe at freemind-tobe.com> : Cycle accurate
|
||||
Blitter emulation.
|
||||
|
||||
- David Savinkoff : More accurate printer emulation, LMC1992 emulation
|
||||
patches, IIR/Low Pass filters and many improvements to the YM2149 model
|
||||
to get a close emulation of the circuit used to merge and filter the
|
||||
output of the 3 YM2149 voices.
|
||||
Great work to enhance the sound quality.
|
||||
|
||||
- Matthias Arndt <marndt at asmsoftware.de> : Wrote the original version
|
||||
of the Hatari user manual, fixed the printer emulation functions.
|
||||
|
||||
- Sébastien Molines <clafou at gmail.com> : Wrote the main part of the
|
||||
Mac OS X GUI of Hatari.
|
||||
|
||||
- Marco Herrn <marco at mherrn.de> : Wrote the initial version of the
|
||||
"man" page of Hatari and maintained the Hatari Debian packages until
|
||||
Hatari was included into Debian.
|
||||
|
||||
- Sven de Marothy : Screenshot functions, the initial CLI debugger,
|
||||
the ACSI emulation and added support for ZIPed and GZIPed disk images.
|
||||
|
||||
- Emmanuel Anne <emanne at absysteme.fr> : Contributed lots of patches,
|
||||
RTC emulation.
|
||||
|
||||
- Tuduri Benoît <skweek at users.sourceforge.net> : French man-page,
|
||||
support for Doxygen.
|
||||
|
||||
- Markus Oberhumer : fixed a problem with ZIPed disk images, routine for
|
||||
loading the configuration file from the $HOME directory.
|
||||
|
||||
- Philippe Gerin : Fixed a bug in the CPU core (bus errors problem).
|
||||
|
||||
- Steve Kemp : Found some possible buffer overflows.
|
||||
|
||||
- George Nakos : Helped to track down a bug in the GEMDOS HD emulation.
|
||||
|
||||
- Pieter van der Meer : Traced a bug in the VIDEL emulation.
|
||||
|
||||
- Patrice Mandin : Some improvements of the autoconf build system files,
|
||||
original author of the DSP emulation core.
|
||||
|
||||
- Martin Doering : Code for compiling the font data into the executable
|
||||
and some other ideas for cleaning up the source code.
|
||||
|
||||
- Matthias Alles : He initiated the port of Hatari to MiNT and helped
|
||||
with a lot of technical questions about the ST.
|
||||
|
||||
- Ventzislav Tzvetkov : Joystick closing patch, Hatari for AmigaOS.
|
||||
|
||||
- "Jo" (?) : Patches for compiling Hatari on a 64-bit Alpha machine.
|
||||
|
||||
- Stefan Berndtsson <stefan at nocrew.org> : Patches to get Hatari
|
||||
running on big endian machines.
|
||||
|
||||
- Anatol Paruntik (?) : Patches for compiling Hatari on QNX.
|
||||
|
||||
- Claus Windeler <goodoldgames at beemulated.net> : BeOS adaption.
|
||||
|
||||
- James Lampard : Adapted Hatari to Acorn RISC OS machines.
|
||||
|
||||
- Mark Keates : Patches for compiling Hatari with MinGW.
|
||||
|
||||
- Fredrik Noring : Tracked down a bug in the blitter emulation and a
|
||||
bug in the PSG shadow register emulation.
|
||||
|
||||
- Volker Seebode: Fix to ASCI emulation to get other than AHDI drivers
|
||||
working.
|
||||
|
||||
- Cyprian Konador: Found some bugs in the blitter cycles emulation,
|
||||
duochrome and samplehold modes for TT video emulation.
|
||||
|
||||
- Jerome Vernet: Some updates to the OS X Xcode project file and OS X
|
||||
GUI, supplied a french keymapping file for OS X.
|
||||
|
||||
- Kenneth Kaufman: MS VC6 & C++ compiler and multiple GEMDOS HD
|
||||
partition support patches.
|
||||
|
||||
- Uwe Seimet: IDE emulation improvements and GEMDOS HD emulation
|
||||
improvement suggestions.
|
||||
|
||||
- Anders Eriksson (Evil/DHS): Helped improving STE's emulation by
|
||||
running many tests programs and providing the source code for some
|
||||
non-working demos.
|
||||
|
||||
- Markus Fritze: New m68k disassembler with more Motorola like syntax
|
||||
and options for controlling how the output looks.
|
||||
|
||||
- Deniz Turkoglu: Patches for the Max OS X GUI.
|
||||
|
||||
- Markus Heiden: SCSI class 1 (ICD) command support for drives > 1 GB
|
||||
|
||||
- nash67: tested hundreds (!) of games from various CD compilations
|
||||
and reported the non working ones on atari-forum.com. Huge thanks for
|
||||
that tedious work, it helped tracking down some less common cases
|
||||
not used in demos (keyboard, joystick, FDC, tos, ...).
|
||||
|
||||
- Gilles Fetis: fixes to MMU emulation (from NeXT emulator project
|
||||
using Hatari code).
|
||||
|
||||
- Peter Putnik (Petari, AtariZoll): for helping with tracking the cause
|
||||
of the crash in Microprose Golf (FDC emulation). Also wrote some useful tools
|
||||
to handle floppies (flofor, floimg), as well as opcovat.tos to report
|
||||
valid/invalid opcodes with a real CPU and under emulation by testing all possible
|
||||
opcode combinations.
|
||||
|
||||
- Jean Louis Guerin (DrCoolZic): for the 'Panzer' program, very useful to test
|
||||
some FDC behaviours and timings on real hardware and to compare them
|
||||
with the emulated system. Also wrote some nice docs on WD1772
|
||||
and methods commonly used for games' protections.
|
||||
|
||||
- Christer Solskogen: for setting up an automatic build script on his site,
|
||||
with up to date binary versions for Linux and Windows in 32 and 64 bit mode.
|
||||
Very useful for end users wishing to try the devel version of Hatari, and
|
||||
lots of interesting build logs too for various cpu architectures.
|
||||
See http://antarctica.no/~hatari/latest
|
||||
|
||||
- Max Böhm: host <-> Atari filename encoding conversion routines and
|
||||
related changes needed to gemdos.c.
|
||||
|
||||
|
||||
Code from other projects
|
||||
------------------------
|
||||
|
||||
As a true open source project, Hatari also uses some code from other
|
||||
projects which we would like to acknowledge here:
|
||||
|
||||
- Most of the original ST hardware emulation comes from the WinSTon
|
||||
source code which has been written by Paul Bates.
|
||||
(http://www.sourceforge.net/projects/winston/)
|
||||
|
||||
- The original CPU core has been taken from UAE which has been written
|
||||
by Bernd Schmidt and others. (http://uae.coresystems.de/)
|
||||
|
||||
- The new alternative CPU core has been taken from WinUAE which is
|
||||
maintained by Toni Wilen. Huge thanks to Toni for accepting ideas
|
||||
and patches not specific to Amiga emulation, as well as keeping on
|
||||
improving the accuracy of 68000/20/30 CPU. (http://www.winuae.net/)
|
||||
|
||||
- Some parts have been taken from the emulator STonX that has been
|
||||
written by Marinos Yannikos and Martin Griffiths.
|
||||
(http://stonx.sourceforge.net/)
|
||||
|
||||
- A lot of code (e.g. the scancode keyboard mapping, Videl, NVRAM and
|
||||
DSP emulation) has been adapted from the sources of the emulator
|
||||
Aranym. (http://aranym.atari.org/)
|
||||
|
||||
- The code for decompressing ZIP files (unzip.c) has been taken from
|
||||
Gilles Vollant's miniunzip program.
|
||||
(http://www.winimage.com/zLibDll/unzip.html)
|
||||
|
||||
- The routines for saving and loading the ASCII configuration file
|
||||
(cfgopts.c) have originally been written by Jeffry J. Brickley.
|
||||
|
||||
- The new sound core uses (or used) some code/ideas from the following GPL
|
||||
projects :
|
||||
* 5 bits volume table and 16*16*16 combinations of all volume are
|
||||
from Sc68 by Benjamin Gerard.
|
||||
* 4 bits to 5 bits volume interpolation from 16*16*16 to 32*32*32
|
||||
are from YM blep synthesis by Antti Lankila.
|
||||
* Since Hatari 1.7, volume table based on measures by Paulo Simoes
|
||||
|
||||
- The IDE hard disk emulation is based on code from QEMU.
|
||||
(http://www.qemu.org/)
|
||||
|
||||
- The MMU emulation for the 68030 has been taken from the NeXT emulator
|
||||
Previous (thanks to Andreas Grabher!). Since Hatari 1.9, this is now
|
||||
taken from WinUAE which uses the same code base.
|
||||
|
35504
doc/changelog.txt
Normal file
37
doc/coding.txt
Normal file
@ -0,0 +1,37 @@
|
||||
|
||||
Hatari coding guidelines
|
||||
========================
|
||||
|
||||
Before writing new code or changing existing files, please read through these
|
||||
coding guidelines to make sure that your changes are in harmony with the
|
||||
existing source code.
|
||||
|
||||
- all source text files have to use Unix Line ending convention (line-feed only)
|
||||
(exception: Code like cart_asm.s which has to be compiled from the Atari TOS
|
||||
side should have DOS line endings (CR-LF) instead).
|
||||
|
||||
- Avoid non-ASCII characters in source code. Use UTF-8 encoding for non-english
|
||||
documentation files if necessary.
|
||||
|
||||
- Use TABs for indentation at the beginning of a line. Default TAB width is 8,
|
||||
but your source code should also look fine with other TAB width (e.g. 4).
|
||||
|
||||
- Use doxygen-style comments to document what each function is doing.
|
||||
|
||||
- No "magic" variable values. Use either defines or enums to name the
|
||||
values and document what they mean if it's not obvious.
|
||||
|
||||
- Hatari uses code from many projects, e.g. the UAE CPU files, which
|
||||
use another coding style than the main source code. We keep the
|
||||
original coding style there for compatibility with the origin. So
|
||||
always try to adapt to the coding style of the file that you're
|
||||
currently editing.
|
||||
|
||||
- For new files, pick one of the existing coding styles, don't add a new one.
|
||||
|
||||
- Try to avoid including a header file from within another header file.
|
||||
Include all necessary header files in the right order in the *.c files
|
||||
instead. Including a header file from within another header file easily leads
|
||||
to a dependency hell which can become very painful when one of the header
|
||||
files clashes with a system header for example and must only be included
|
||||
in certain .c files only.
|
3983
doc/compatibility.html
Normal file
8
doc/de/tastatur-windows.txt
Normal file
@ -0,0 +1,8 @@
|
||||
# Below is a keymap file for Hatari running on Windows, which maps the SDL
|
||||
# keys of a German PC keyboard to the corresponding Atari ST scancodes.
|
||||
|
||||
45,12 # ß
|
||||
91,26 # Ü
|
||||
93,27 # +
|
||||
92,41 # #
|
||||
96,43 # ~
|
240
doc/doxygen/Doxyfile
Normal file
@ -0,0 +1,240 @@
|
||||
# Doxyfile 1.5.1-p1
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Project related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
PROJECT_NAME = Hatari
|
||||
PROJECT_NUMBER = 1.9.0
|
||||
OUTPUT_DIRECTORY = .
|
||||
CREATE_SUBDIRS = NO
|
||||
OUTPUT_LANGUAGE = English
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
ABBREVIATE_BRIEF = "The $name class" \
|
||||
"The $name widget" \
|
||||
"The $name file" \
|
||||
is \
|
||||
provides \
|
||||
specifies \
|
||||
contains \
|
||||
represents \
|
||||
a \
|
||||
an \
|
||||
the
|
||||
ALWAYS_DETAILED_SEC = NO
|
||||
INLINE_INHERITED_MEMB = NO
|
||||
FULL_PATH_NAMES = YES
|
||||
STRIP_FROM_PATH =
|
||||
STRIP_FROM_INC_PATH =
|
||||
SHORT_NAMES = NO
|
||||
JAVADOC_AUTOBRIEF = NO
|
||||
MULTILINE_CPP_IS_BRIEF = NO
|
||||
INHERIT_DOCS = YES
|
||||
SEPARATE_MEMBER_PAGES = NO
|
||||
TAB_SIZE = 8
|
||||
ALIASES =
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
OPTIMIZE_OUTPUT_JAVA = NO
|
||||
BUILTIN_STL_SUPPORT = NO
|
||||
DISTRIBUTE_GROUP_DOC = NO
|
||||
SUBGROUPING = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Build related configuration options
|
||||
#---------------------------------------------------------------------------
|
||||
EXTRACT_ALL = YES
|
||||
EXTRACT_PRIVATE = YES
|
||||
EXTRACT_STATIC = YES
|
||||
EXTRACT_LOCAL_CLASSES = YES
|
||||
EXTRACT_LOCAL_METHODS = NO
|
||||
HIDE_UNDOC_MEMBERS = NO
|
||||
HIDE_UNDOC_CLASSES = NO
|
||||
HIDE_FRIEND_COMPOUNDS = NO
|
||||
HIDE_IN_BODY_DOCS = NO
|
||||
INTERNAL_DOCS = NO
|
||||
CASE_SENSE_NAMES = NO
|
||||
HIDE_SCOPE_NAMES = NO
|
||||
SHOW_INCLUDE_FILES = YES
|
||||
INLINE_INFO = YES
|
||||
SORT_MEMBER_DOCS = YES
|
||||
SORT_BRIEF_DOCS = NO
|
||||
SORT_BY_SCOPE_NAME = NO
|
||||
GENERATE_TODOLIST = YES
|
||||
GENERATE_TESTLIST = YES
|
||||
GENERATE_BUGLIST = YES
|
||||
GENERATE_DEPRECATEDLIST= YES
|
||||
ENABLED_SECTIONS =
|
||||
MAX_INITIALIZER_LINES = 30
|
||||
SHOW_USED_FILES = YES
|
||||
SHOW_DIRECTORIES = NO
|
||||
FILE_VERSION_FILTER =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to warning and progress messages
|
||||
#---------------------------------------------------------------------------
|
||||
QUIET = NO
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_NO_PARAMDOC = NO
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
WARN_LOGFILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the input files
|
||||
#---------------------------------------------------------------------------
|
||||
INPUT = ../../src
|
||||
FILE_PATTERNS = *.c \
|
||||
*.cc \
|
||||
*.cxx \
|
||||
*.cpp \
|
||||
*.c++ \
|
||||
*.h \
|
||||
*.hh \
|
||||
*.hxx \
|
||||
*.hpp \
|
||||
*.h++
|
||||
RECURSIVE = YES
|
||||
EXCLUDE =
|
||||
EXCLUDE_SYMLINKS = NO
|
||||
EXCLUDE_PATTERNS =
|
||||
EXAMPLE_PATH =
|
||||
EXAMPLE_PATTERNS = *
|
||||
EXAMPLE_RECURSIVE = NO
|
||||
IMAGE_PATH =
|
||||
INPUT_FILTER =
|
||||
FILTER_PATTERNS =
|
||||
FILTER_SOURCE_FILES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to source browsing
|
||||
#---------------------------------------------------------------------------
|
||||
SOURCE_BROWSER = YES
|
||||
INLINE_SOURCES = NO
|
||||
STRIP_CODE_COMMENTS = NO
|
||||
REFERENCED_BY_RELATION = YES
|
||||
REFERENCES_RELATION = YES
|
||||
REFERENCES_LINK_SOURCE = YES
|
||||
USE_HTAGS = NO
|
||||
VERBATIM_HEADERS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the alphabetical class index
|
||||
#---------------------------------------------------------------------------
|
||||
ALPHABETICAL_INDEX = NO
|
||||
COLS_IN_ALPHA_INDEX = 5
|
||||
IGNORE_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the HTML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = html
|
||||
HTML_FILE_EXTENSION = .html
|
||||
HTML_HEADER =
|
||||
HTML_FOOTER =
|
||||
HTML_STYLESHEET =
|
||||
HTML_ALIGN_MEMBERS = YES
|
||||
GENERATE_HTMLHELP = YES
|
||||
CHM_FILE =
|
||||
HHC_LOCATION =
|
||||
GENERATE_CHI = NO
|
||||
BINARY_TOC = NO
|
||||
TOC_EXPAND = NO
|
||||
DISABLE_INDEX = NO
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
GENERATE_TREEVIEW = NO
|
||||
TREEVIEW_WIDTH = 250
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the LaTeX output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_LATEX = NO
|
||||
LATEX_OUTPUT = latex
|
||||
LATEX_CMD_NAME = latex
|
||||
MAKEINDEX_CMD_NAME = makeindex
|
||||
COMPACT_LATEX = NO
|
||||
PAPER_TYPE = a4wide
|
||||
EXTRA_PACKAGES =
|
||||
LATEX_HEADER =
|
||||
PDF_HYPERLINKS = NO
|
||||
USE_PDFLATEX = NO
|
||||
LATEX_BATCHMODE = NO
|
||||
LATEX_HIDE_INDICES = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the RTF output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_RTF = NO
|
||||
RTF_OUTPUT = rtf
|
||||
COMPACT_RTF = NO
|
||||
RTF_HYPERLINKS = NO
|
||||
RTF_STYLESHEET_FILE =
|
||||
RTF_EXTENSIONS_FILE =
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the man page output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_MAN = NO
|
||||
MAN_OUTPUT = man
|
||||
MAN_EXTENSION = .3
|
||||
MAN_LINKS = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the XML output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_XML = NO
|
||||
XML_OUTPUT = xml
|
||||
XML_SCHEMA =
|
||||
XML_DTD =
|
||||
XML_PROGRAMLISTING = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options for the AutoGen Definitions output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_AUTOGEN_DEF = NO
|
||||
#---------------------------------------------------------------------------
|
||||
# configuration options related to the Perl module output
|
||||
#---------------------------------------------------------------------------
|
||||
GENERATE_PERLMOD = NO
|
||||
PERLMOD_LATEX = NO
|
||||
PERLMOD_PRETTY = YES
|
||||
PERLMOD_MAKEVAR_PREFIX =
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the preprocessor
|
||||
#---------------------------------------------------------------------------
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = NO
|
||||
EXPAND_ONLY_PREDEF = NO
|
||||
SEARCH_INCLUDES = YES
|
||||
INCLUDE_PATH =
|
||||
INCLUDE_FILE_PATTERNS =
|
||||
PREDEFINED =
|
||||
EXPAND_AS_DEFINED =
|
||||
SKIP_FUNCTION_MACROS = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::additions related to external references
|
||||
#---------------------------------------------------------------------------
|
||||
TAGFILES =
|
||||
GENERATE_TAGFILE =
|
||||
ALLEXTERNALS = NO
|
||||
EXTERNAL_GROUPS = YES
|
||||
PERL_PATH = /usr/bin/perl
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration options related to the dot tool
|
||||
#---------------------------------------------------------------------------
|
||||
CLASS_DIAGRAMS = NO
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = NO
|
||||
CLASS_GRAPH = YES
|
||||
COLLABORATION_GRAPH = YES
|
||||
GROUP_GRAPHS = YES
|
||||
UML_LOOK = NO
|
||||
TEMPLATE_RELATIONS = NO
|
||||
INCLUDE_GRAPH = YES
|
||||
INCLUDED_BY_GRAPH = YES
|
||||
CALL_GRAPH = NO
|
||||
CALLER_GRAPH = NO
|
||||
GRAPHICAL_HIERARCHY = YES
|
||||
DIRECTORY_GRAPH = YES
|
||||
DOT_IMAGE_FORMAT = png
|
||||
DOT_PATH =
|
||||
DOTFILE_DIRS =
|
||||
MAX_DOT_GRAPH_DEPTH = 1000
|
||||
DOT_TRANSPARENT = NO
|
||||
DOT_MULTI_TARGETS = NO
|
||||
GENERATE_LEGEND = YES
|
||||
DOT_CLEANUP = YES
|
||||
#---------------------------------------------------------------------------
|
||||
# Configuration::additions related to the search engine
|
||||
#---------------------------------------------------------------------------
|
||||
SEARCHENGINE = NO
|
1218
doc/emutos.txt
Normal file
36
doc/fr/clavier-exemple.txt
Normal file
@ -0,0 +1,36 @@
|
||||
# This is an example for a keyboard mapping file that can be used in Hatari
|
||||
# by loading it from the keyboard setup dialog.
|
||||
#
|
||||
# Lines starting with a '#' or with a ';' are comments.
|
||||
# All other lines should contain exactly two numbers separated by a comma.
|
||||
# The first number is the symbolic PC key code (see the SDL_keysym.h file
|
||||
# from the SDL library header files usually in /usr/include/SDL/).
|
||||
# The corresponding key will be mapped to the ST key which is specified by
|
||||
# second number - the ST scan code of the key (see src/keymap.c in the Hatari
|
||||
# sources).
|
||||
#
|
||||
# Here is an example for a french keymap for the MacBook:
|
||||
97,16
|
||||
122,17
|
||||
113,30
|
||||
109,39
|
||||
119,44
|
||||
38,2
|
||||
160,3
|
||||
34,4
|
||||
39,5
|
||||
40,6
|
||||
161,7
|
||||
163,8
|
||||
33,9
|
||||
162,10
|
||||
164,11
|
||||
29,12
|
||||
45,13
|
||||
94,26
|
||||
36,27
|
||||
165,40
|
||||
44,50
|
||||
59,51
|
||||
58,52
|
||||
61,53
|
277
doc/fr/hatari.1
Normal file
@ -0,0 +1,277 @@
|
||||
.\" Hey, EMACS: -*- nroff -*-
|
||||
.\" First parameter, NAME, should be all caps
|
||||
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
||||
.\" other parameters are allowed: see man(7), man(1)
|
||||
.TH "HATARI" "1" "2008-03-14" "Hatari" ""
|
||||
.\" Please adjust this date whenever revising the manpage.
|
||||
|
||||
.SH "NAME"
|
||||
Hatari \- emulateur Atari ST(e)
|
||||
.SH "SYNOPSIS"
|
||||
.B hatari
|
||||
.RI [options]
|
||||
.RI [diskimage]
|
||||
.SH "DESCRIPTION"
|
||||
Hatari est un emulateur d'Atari ST(e) pour Linux, FreeBSD, BeOS ainsi
|
||||
que tout systemes d'exploitation supportant la bibliotheque SDL.
|
||||
.PP
|
||||
Avec Hatari vous pouvez lancer des jeux, demos ou des applications
|
||||
ecrites pour l'Atari ST ou STE.
|
||||
Il supporte egalement les images de disquettes les plus couramment
|
||||
utilisees a savoir *.st et *.msa. Il permet aussi l'emulation de
|
||||
disque dur.
|
||||
.PP
|
||||
Pour lancer l'emulateur une image ROM du TOS est requise. EmuTOS
|
||||
est une implementation libre du TOS fournie avec Hatari.
|
||||
Malheureusement cette derniere n'est pas entierement compatible avec
|
||||
le TOS original donc certains programmes risquent de ne pas
|
||||
fonctionner correctement. Pour cela, il est recommande d'utiliser
|
||||
une ROM TOS issue d'un veritable Atari.
|
||||
.SH "OPTIONS"
|
||||
Les options sont classées en sous catégories:
|
||||
.SH "Options générale"
|
||||
.TP
|
||||
.B \-h, \-\-help
|
||||
affiche les options de la ligne de commande
|
||||
.TP
|
||||
.B \-v, \-\-version
|
||||
affiche les informations sur la version
|
||||
.TP
|
||||
.B \-\-confirm-quit <bool>
|
||||
Whether Hatari confirms quitting
|
||||
.TP
|
||||
.B \-c, \-\-configfile <filename>
|
||||
utilise un fichier nomme explicitement comme fichier de configuration
|
||||
en lieu et place du ~/.hatari/hatari.cfg
|
||||
.SH "Options d'écran
|
||||
.TP
|
||||
.B \-\-monitor <x>
|
||||
selectionne le type de moniteur (x = mono/rgb/vga/tv)
|
||||
.TP
|
||||
.B \-f, \-\-fullscreen
|
||||
demarre l'emulateur en mode plein ecran
|
||||
.TP
|
||||
.B \-w, \-\-window
|
||||
demarre l'emulateur en mode fenetre
|
||||
.TP
|
||||
.B \-z, \-\-zoom <x>
|
||||
agrandir les petites résolutions (1=non, 2=oui)
|
||||
.TP
|
||||
.B \-\-frameskips <x>
|
||||
Saute <x> images apres chaque image affichees pour accelerer l'emulation
|
||||
(0 <= x <= 8)
|
||||
.TP
|
||||
.B \-\-borders <bool>
|
||||
Show screen borders (for overscan demos etc)
|
||||
.TP
|
||||
.B \-\-spec512 <x>
|
||||
Hatari uses this threshold to decide when to render a screen with
|
||||
the slower but more accurate Spectrum512 screen conversion functions
|
||||
(0 <= x <= 512, 0=disable)
|
||||
.TP
|
||||
.B \-\-bpp <bool>
|
||||
Force given internal bitdepth (x=8/16/32, x=0 for autodetection).
|
||||
8-bit color depth may be useful for older host computers
|
||||
.SH "Options de VDI"
|
||||
.TP
|
||||
.B \-\-vdi\-planes <x>
|
||||
utilise une resolution VDI etendue avec une profondeur de bit de <x>
|
||||
(x = 1, 2 or 4)
|
||||
.TP
|
||||
.B \-\-vdi\-width <w>
|
||||
utilise une resolution VDI etendue avec une largeur de <w> (384 <= w <= 1024)
|
||||
.TP
|
||||
.B \-\-vdi\-height <h>
|
||||
utilise une resolution VDI etendue avec une hauteur de <h> (200 < h <= 768)
|
||||
.SH "Options d'interface"
|
||||
.TP
|
||||
.B \-j, \-\-joystick <port>
|
||||
emule le joystick ST sur le <port> 0 ou 1 avec le clavier
|
||||
.TP
|
||||
.B \-\-printer <file>
|
||||
active le support de l'imprimante et ecrit les donnees dans le fichier <file>
|
||||
.TP
|
||||
.B \-\-midi <filename>
|
||||
active la sortie MIDI experimentale vers un fichier mentionne par un nom
|
||||
.TP
|
||||
.B \-\-rs232 <filename>
|
||||
active l'emulation experimentale du RS232 via un fichier/device
|
||||
nomme explicitement
|
||||
.SH "Options des disques"
|
||||
.TP
|
||||
.B \-d, \-\-harddrive <dir>
|
||||
utilise <dir> comme un disque dur emule
|
||||
.TP
|
||||
.B \-\-acsi <file>
|
||||
emule un disque dur ACSI avec un fichier image <file>
|
||||
.TP
|
||||
.B \-\-fastfdc <bool>
|
||||
accelere l'emulation du FDC (peut entrainer des erreurs dans certains jeux ou demos)
|
||||
.SH "Options de mémoire"
|
||||
.TP
|
||||
.B \-s, \-\-memsize <x>
|
||||
fixe une quantite de memoire pour la RAM emulee, x = 1 a 14 MiB,
|
||||
ou 0 pour 512 Ko
|
||||
.TP
|
||||
.B \-t, \-\-tos <imagefile>
|
||||
specifie une image ROM TOS a utiliser
|
||||
.TP
|
||||
.B \-\-cartridge <imagefile>
|
||||
utilise une image ROM de cartouche <file> (fonctionne uniquement si
|
||||
l'emulation de disque dur et VDI etendue sont desactivee)
|
||||
.TP
|
||||
.B \-\-memstate <file>
|
||||
Load memory snap-shot <file>
|
||||
.SH "Option du processeur"
|
||||
.TP
|
||||
.B \-\-cpulevel <x>
|
||||
specifie un CPU (680x0) a utiliser (TOS 2.06 uniquement!!)
|
||||
.TP
|
||||
.B \-\-cpuclock <x>
|
||||
Set the CPU clock (8, 16 or 32 Mhz)
|
||||
.TP
|
||||
.B \-\-compatible <bool>
|
||||
utilise le mode de compatibilite plus fidele mais plus lent
|
||||
que le mode 68000
|
||||
.SH "Options diverses du système"
|
||||
.TP
|
||||
.B \-\-machine <x>
|
||||
selectionne un type de machine (x = st, ste, tt ou falcon)
|
||||
.TP
|
||||
.B \-\-blitter <bool>
|
||||
active l'emulation du blitter
|
||||
.TP
|
||||
.B \-\-dsp <x>
|
||||
emulation du DSP du Falcon (x = aucune, factice ou emulee)
|
||||
.TP
|
||||
.B \-\-sound <x>
|
||||
Régle le son (x=off/low/med/hi)
|
||||
.TP
|
||||
.B \-\-keymap <file>
|
||||
charge un fichier de refinition du clavier de <file>
|
||||
.SH "Options de déboguer"
|
||||
.TP
|
||||
.B \-D, \-\-debug
|
||||
active le deboggueur integre
|
||||
.TP
|
||||
.B \-\-log <file>
|
||||
Sauvegarde le rapport vers le fichier <file> (peut aussi etre "stdout" ou
|
||||
"stderr")
|
||||
.TP
|
||||
.B \-\-trace <trace1,...>
|
||||
Activate debug traces, see \-\-trace help for tracing options
|
||||
|
||||
.SH "COMMANDS"
|
||||
|
||||
Les touches de raccourcis peuvent etre parametrees dans le fichier
|
||||
de configurations.
|
||||
Par defaut, les parametres sont:
|
||||
.TP
|
||||
.B AltGr + a
|
||||
enregistre l'animation
|
||||
.TP
|
||||
.B AltGr + g
|
||||
fait une capture d'ecran
|
||||
.TP
|
||||
.B AltGr + i
|
||||
touche patron: quitte le mode plein ecran et met la fenetre en icone
|
||||
.TP
|
||||
.B AltGr + j
|
||||
active l'emulation joystick via les touches de directions
|
||||
.TP
|
||||
.B AltGr + m
|
||||
(active/desactive) la souris dans la fenetre
|
||||
.TP
|
||||
.B AltGr + r
|
||||
eteint le ST (a chaud)
|
||||
.TP
|
||||
.B AltGr + c
|
||||
eteint le ST a froid (comme le bouton original d'allumage)
|
||||
.TP
|
||||
.B AltGr + s
|
||||
active/desactive le son
|
||||
.TP
|
||||
.B AltGr + q
|
||||
quitte l'emulateur
|
||||
.TP
|
||||
.B AltGr + x
|
||||
change la vitesse normale/maximum
|
||||
.TP
|
||||
.B AltGr + y
|
||||
active/desactive l'enregistrement du son
|
||||
.TP
|
||||
.B AltGr + k
|
||||
sauvegarde l'etat de la memoire
|
||||
.TP
|
||||
.B AltGr + l
|
||||
restaure l'etat de la memoire
|
||||
.TP
|
||||
.B F11
|
||||
change le mode entre plein ecran et fenetre
|
||||
.TP
|
||||
.B F12
|
||||
active les commandes GUI de Hatari
|
||||
.br
|
||||
Vous pouvez avoir besoin de tenir la touche SHIFT en mode fenetre
|
||||
.TP
|
||||
.B Pause
|
||||
Ouvrira le deboggueur, s'il etait active avec l'option \-\-debug
|
||||
|
||||
.SH Clavier d'Atari ST emule
|
||||
Toutes les autres touches du clavier PC agissent comme celles de Atari ST
|
||||
donc si vous appuyez sur ESPACE sur votre PC il en resultera sur
|
||||
le clavier d'Atari ST un appuis sur la touche ESPACE. Les touches suivantes
|
||||
ont une signification speciales :
|
||||
.TP
|
||||
.B Alt
|
||||
Agira comme la touche ALTERNATE du clavier ST
|
||||
.TP
|
||||
.B left Ctrl
|
||||
Agira comme la touche CONTROL du clavier ST
|
||||
.TP
|
||||
.B Page Up
|
||||
Emulera la touche HELP du clavier ST
|
||||
.TP
|
||||
.B Page Down
|
||||
Emulera la touche UNDO du clavier ST
|
||||
.PP
|
||||
.B AltGr
|
||||
Agira comme
|
||||
.B Alternate
|
||||
tel sauf si vous appuyez sur les touches speciales d'Hatari.
|
||||
|
||||
La touche
|
||||
.B right Ctrl
|
||||
est utilisee comme le bouton feu d'un joystick emule
|
||||
que vous aurez active precedement par l'emulation du joystick via
|
||||
les touches du clavier.
|
||||
|
||||
Le touche de directions agiront comme les touches de directions sur
|
||||
l'Atari ST tant que l'emulation du joystick par le clavier est inactive.
|
||||
.SH "VOIR AUSSI"
|
||||
La documentation originale du programme, habituellement
|
||||
en /usr/share/doc/.
|
||||
.PP
|
||||
La page d'accueil d'Hatari : http://hatari.tuxfamily.org/
|
||||
|
||||
.SH "FICHIERS"
|
||||
.TP
|
||||
/etc/hatari.cfg (ou /usr/local/etc/hatari.cfg)
|
||||
le fichier de configuration global d'Hatari
|
||||
.TP
|
||||
~/.hatari/hatari.cfg
|
||||
Le fichier de configuration de l'utilisateur personnel
|
||||
d'Hatari
|
||||
.TP
|
||||
tos.img
|
||||
L'image ROM du TOS qui sera charge a partir du repertoire de donnees d'Hatari
|
||||
si aucun argument n'est specifie sur la ligne de commande ou dans le fichier
|
||||
de configuration.
|
||||
|
||||
.SH "AUTEURS"
|
||||
Cette page du manuel a ete ecrite par Marco Herrn <marco@mherrn.de>,
|
||||
pour le projet Debian et modifiee par la suite par Thomas Huth pour les
|
||||
versions plus recentes d'Hatari
|
||||
|
||||
.SH "TRADUCTEUR"
|
||||
Benoît TUDURI <skweek@users.sourceforge.net>
|
647
doc/hatari.1
Normal file
@ -0,0 +1,647 @@
|
||||
.\" Hey, EMACS: -*- nroff -*-
|
||||
.\" First parameter, NAME, should be all caps
|
||||
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
||||
.\" other parameters are allowed: see man(7), man(1)
|
||||
.TH "HATARI" "1" "2014-05-08" "Hatari" ""
|
||||
.\" Please adjust this date whenever revising the manpage.
|
||||
|
||||
.SH "NAME"
|
||||
hatari \- Atari ST/STE/TT/Falcon emulator
|
||||
|
||||
.SH "SYNOPSIS"
|
||||
.B hatari
|
||||
.RI [options]
|
||||
.RI [directory|diskimage|program]
|
||||
|
||||
.SH "DESCRIPTION"
|
||||
Hatari is an Atari ST/STE/TT/Falcon emulator for Linux, FreeBSD, BeOS and
|
||||
other Systems which are supported by the SDL library.
|
||||
.PP
|
||||
With hatari one can run games, demos or applications written for Atari
|
||||
ST, STE or Falcon. Atari TT support is experimental. Hatari supports
|
||||
the commonly used *.st and *.msa disk images and hard disk emulation.
|
||||
.PP
|
||||
To run the emulator a TOS ROM image is needed. EmuTOS, a free
|
||||
implementation of TOS is shipped with hatari. Since it is not yet
|
||||
fully compatible with the original TOS, some programs won't run
|
||||
correctly with it. Because of this it is recommended to use a TOS
|
||||
ROM from a real Atari.
|
||||
.PP
|
||||
As an argument one can give either a name of a directory that should
|
||||
be emulated as a virtual GEMDOS hard disk, a floppy disk image or an
|
||||
Atari program that should be autostarted. In the last case the
|
||||
program's directory will be used as the C: drive from where this
|
||||
program will be started.
|
||||
.PP
|
||||
Booting will be done from the disk image or directory that's given
|
||||
last on the command line as an option or the argument (and which
|
||||
corresponds to A: or C:). If you want to give floppy image name with
|
||||
an autostarting program name, give it with --disk-a option before the
|
||||
program name.
|
||||
|
||||
.SH "OPTIONS"
|
||||
Hatari options are split into several categories:
|
||||
|
||||
.SH "General options"
|
||||
.TP
|
||||
.B \-h, \-\-help
|
||||
Print command line options and terminate
|
||||
.TP
|
||||
.B \-v, \-\-version
|
||||
Print version information and terminate
|
||||
.TP
|
||||
.B \-\-confirm\-quit <bool>
|
||||
Whether Hatari confirms quitting
|
||||
.TP
|
||||
.B \-c, \-\-configfile <filename>
|
||||
Read additional configuration values from <file>, these
|
||||
override values read from the global and user configuration
|
||||
files
|
||||
.TP
|
||||
.B \-k, \-\-keymap <file>
|
||||
Load keyboard mapping from <file>
|
||||
.TP
|
||||
.B \-\-fast\-forward <bool>
|
||||
On fast machine helps skipping (fast forwarding) Hatari output
|
||||
|
||||
.SH "Common display options"
|
||||
.TP
|
||||
.B \-m, \-\-mono
|
||||
Start in monochrome mode instead of color
|
||||
.TP
|
||||
.B \-\-monitor <x>
|
||||
Select monitor type (x = mono/rgb/vga/tv)
|
||||
.TP
|
||||
.B \-f, \-\-fullscreen
|
||||
Start the emulator in fullscreen mode
|
||||
.TP
|
||||
.B \-w, \-\-window
|
||||
Start the emulator in windowed mode
|
||||
.TP
|
||||
.B \-\-grab
|
||||
Grab mouse (also) in windowed mode
|
||||
.TP
|
||||
.B \-\-borders <bool>
|
||||
Show ST/STE/Falcon screen borders (for low/med resolution overscan demos)
|
||||
.TP
|
||||
.B \-\-frameskips <x>
|
||||
Skip <x> frames after each displayed frame to accelerate emulation
|
||||
(0=disabled, >4 uses automatic frameskip with given value as maximum)
|
||||
.TP
|
||||
.B \-\-slowdown <x>
|
||||
Slow down emulation by factor of x (used as multiplier for VBL wait time)
|
||||
.TP
|
||||
.B \-\-mousewarp <bool>
|
||||
To keep host mouse better in sync with Atari mouse pointer, center it
|
||||
to Hatari window on cold reset and resolution changes
|
||||
.TP
|
||||
.B \-\-statusbar <bool>
|
||||
Show statusbar (with floppy leds etc etc)
|
||||
.TP
|
||||
.B \-\-drive\-led <bool>
|
||||
Show overlay drive led when statusbar isn't shown
|
||||
.TP
|
||||
.B \-\-max\-width <x>
|
||||
Preferred / maximum window width for borders / zooming
|
||||
.TP
|
||||
.B \-\-max\-height <x>
|
||||
Preferred / maximum window height for borders / zooming
|
||||
.TP
|
||||
.B \-\-bpp <bool>
|
||||
Force internal bitdepth (x = 8/15/16/32, 0=disable)
|
||||
|
||||
.SH "ST/STE specific display options"
|
||||
.TP
|
||||
.B \-\-desktop\-st <bool>
|
||||
Whether fullscreen mode uses desktop resolution to avoid: messing
|
||||
multi-screen setups, several seconds delay needed by LCD monitors
|
||||
resolution switching and the resulting sound break. As Hatari ST/E
|
||||
display code doesn't support zooming (except low-rez doubling), it
|
||||
doesn't get scaled (by Hatari or monitor) when this is enabled.
|
||||
Therefore this is mainly useful only if you suffer from the described
|
||||
effects, but still want to grab mouse and remove other distractions
|
||||
from the screen just by toggling fullscreen mode. (disabled by default)
|
||||
.TP
|
||||
.B \-\-spec512 <x>
|
||||
Hatari uses this threshold to decide when to render a screen with
|
||||
the slower but more accurate Spectrum512 screen conversion functions
|
||||
(0 <= x <= 512, 0=disable)
|
||||
.TP
|
||||
.B \-z, \-\-zoom <x>
|
||||
Zoom (double) low resolution (1=no, 2=yes)
|
||||
|
||||
.SH "TT/Falcon specific display options"
|
||||
Zooming to sizes specified below is internally done using integer scaling
|
||||
factors. This means that different Atari resolutions may show up with
|
||||
different sizes, but they are never blurry.
|
||||
.TP
|
||||
.B \-\-desktop <bool>
|
||||
Whether to use desktop resolution on fullscreen to avoid issues
|
||||
related to resolution switching. Otherwise fullscreen will use
|
||||
a resolution that is closest to the Hatari window size.
|
||||
(enabled by default)
|
||||
.TP
|
||||
.B \-\-force\-max <bool>
|
||||
Hatari window size is forced to specified maximum size and black borders
|
||||
used when Atari resolution doesn't scale evenly to it. This is most
|
||||
useful when recording videos of Falcon demos that change their
|
||||
resolution. (disabled by default)
|
||||
.TP
|
||||
.B \-\-aspect <bool>
|
||||
Whether to do monitor aspect ratio correction (enabled by default)
|
||||
|
||||
.SH "VDI options"
|
||||
.TP
|
||||
.B \-\-vdi <bool>
|
||||
Whether to use VDI screen mode. Doesn't work with TOS v4.
|
||||
TOS v3 memory detection isn't compatible with larger VDI modes
|
||||
(i.e. you need to skip the detection at boot)
|
||||
.TP
|
||||
.B \-\-vdi\-planes <x>
|
||||
Use extended VDI resolution with bit depth <x> (x = 1, 2 or 4)
|
||||
.TP
|
||||
.B \-\-vdi\-width <w>
|
||||
Use extended VDI resolution with width <w> (320 < w <= 1280)
|
||||
.TP
|
||||
.B \-\-vdi\-height <h>
|
||||
Use extended VDI resolution with height <h> (200 < h <= 960)
|
||||
|
||||
.SH "Screen capture options"
|
||||
.TP
|
||||
.B \-\-crop <bool>
|
||||
Remove statusbar from the screen captures
|
||||
.TP
|
||||
.B \-\-avirecord
|
||||
Start AVI recording. Note: recording will automatically
|
||||
stop when emulation resolution changes.
|
||||
.TP
|
||||
.B \-\-avi\-vcodec <x>
|
||||
Select AVI video codec (x = bmp/png). PNG compression can
|
||||
be \fImuch\fP slower than using the uncompressed BMP format,
|
||||
but uncompressed video content takes huge amount of space.
|
||||
.TP
|
||||
.B \-\-png\-level <x>
|
||||
Select PNG compression level for AVI video (x = 0-9).
|
||||
Both compression efficiency and speed depend on the compressed
|
||||
screen content. Highest compression level (9) can be \fIreally\fP
|
||||
slow with some content. Levels 3-6 should compress nearly as well
|
||||
with clearly smaller CPU overhead.
|
||||
.TP
|
||||
.B \-\-avi\-fps <x>
|
||||
Force AVI frame rate (x = 50/60/71/...)
|
||||
.TP
|
||||
.B \-\-avi\-file <file>
|
||||
Use <file> to record AVI
|
||||
|
||||
.SH "Devices options"
|
||||
.TP
|
||||
.B \-j, \-\-joystick <port>
|
||||
Emulate joystick with cursor keys in given port (0-5)
|
||||
.TP
|
||||
.B \-\-joy<port> <type>
|
||||
Set joystick type (none/keys/real) for given port
|
||||
.TP
|
||||
.B \-\-printer <file>
|
||||
Enable printer support and write data to <file>
|
||||
.TP
|
||||
.B \-\-midi\-in <filename>
|
||||
Enable MIDI support and write MIDI data to <file>
|
||||
.TP
|
||||
.B \-\-midi\-out <filename>
|
||||
Enable MIDI support and read MIDI data from <file>
|
||||
.TP
|
||||
.B \-\-rs232\-in <filename>
|
||||
Enable serial port support and use <file> as the input device
|
||||
.TP
|
||||
.B \-\-rs232\-out <filename>
|
||||
Enable serial port support and use <file> as the output device
|
||||
|
||||
.SH "Floppy drive options"
|
||||
.TP
|
||||
.B \-\-drive\-a <bool>
|
||||
Enable/disable drive A (default is on)
|
||||
.TP
|
||||
.B \-\-drive\-b <bool>
|
||||
Enable/disable drive B (default is on)
|
||||
.TP
|
||||
.B \-\-drive\-a\-heads <x>
|
||||
Set number of heads for drive A (1=single sided, 2=double sided)
|
||||
.TP
|
||||
.B \-\-drive\-b\-heads <x>
|
||||
Set number of heads for drive B (1=single sided, 2=double sided)
|
||||
.TP
|
||||
.B \-\-disk\-a <file>
|
||||
Set disk image for floppy drive A
|
||||
.TP
|
||||
.B \-\-disk\-b <file>
|
||||
Set disk image for floppy drive B
|
||||
.TP
|
||||
.B \-\-fastfdc <bool>
|
||||
speed up FDC emulation (can cause incompatibilities)
|
||||
.TP
|
||||
.B \-\-protect\-floppy <x>
|
||||
Write protect floppy image contents (on/off/auto). With "auto" option
|
||||
write protection is according to the disk image file attributes
|
||||
|
||||
.SH "Hard drive options"
|
||||
.TP
|
||||
.B \-d, \-\-harddrive <dir>
|
||||
Emulate harddrive partition(s) with <dir> contents. If directory
|
||||
contains only single letter (C-Z) subdirectories, each of these
|
||||
subdirectories will be treated as a separate partition, otherwise the
|
||||
given directory itself will be assigned to drive "C:". In the multiple
|
||||
partition case, the letters used as the subdirectory names will
|
||||
determine to which drives/partitions they're assigned. If <dir> is
|
||||
an empty string, then harddrive's emulation is disabled
|
||||
.TP
|
||||
.B \-\-protect\-hd <x>
|
||||
Write protect harddrive <dir> contents (on/off/auto). With "auto" option
|
||||
the protection can be controlled by setting individual files attributes
|
||||
as it disables the file attribute modifications for the GEMDOS hard disk
|
||||
emulation
|
||||
.TP
|
||||
.B \-\-gemdos\-case <x>
|
||||
Specify whether new dir/filenames are forced to be in upper or lower case
|
||||
with the GEMDOS HD emulation. Off/upper/lower, off by default
|
||||
.TP
|
||||
.B \-\-gemdos\-conv <bool>
|
||||
Whether GEMDOS file names with 8-bit (non-ASCII) characters are
|
||||
converted between Atari and host character sets. On Linux, host file
|
||||
name character set is assumed to be UTF-8. This option is disabled by
|
||||
default, in case you've transferred files from Atari machine without
|
||||
proper file name conversion (e.g. by zipping them on Atari and
|
||||
unzipping on PC).
|
||||
.TP
|
||||
.B \-\-acsi <id>=<file>
|
||||
Emulate an ACSI hard disk with given BUS ID (0-7) using image <file>.
|
||||
If just filename is given, it's assigned to BUS ID 0.
|
||||
.TP
|
||||
.B \-\-ide\-master <file>
|
||||
Emulate an IDE master hard disk with an image <file>
|
||||
.TP
|
||||
.B \-\-ide\-slave <file>
|
||||
Emulate an IDE slave hard disk with an image <file>
|
||||
|
||||
.SH "Memory options"
|
||||
.TP
|
||||
.B \-\-memstate <file>
|
||||
Load memory snap-shot <file>
|
||||
.TP
|
||||
.B \-s, \-\-memsize <x>
|
||||
Set amount of emulated ST RAM, x = 1 to 14 MiB, or 0 for 512 KiB
|
||||
.TP
|
||||
.B \-s, \-\-ttram <x>
|
||||
Set amount of emulated TT RAM, x = 0 to 256 MiB (in 4MB steps)
|
||||
|
||||
.SH "ROM options"
|
||||
.TP
|
||||
.B \-t, \-\-tos <imagefile>
|
||||
Specify TOS ROM image to use
|
||||
.TP
|
||||
.B \-\-patch\-tos <bool>
|
||||
Use this option to enable/disable TOS ROM patching. Experts only! Leave
|
||||
this enabled unless you know what you are doing!
|
||||
.TP
|
||||
.B \-\-cartridge <imagefile>
|
||||
Use ROM cartridge image <file> (only works if GEMDOS HD emulation and
|
||||
extended VDI resolution are disabled)
|
||||
|
||||
.SH "CPU options"
|
||||
.TP
|
||||
.B \-\-cpulevel <x>
|
||||
Specify CPU (680x0) to use (use x >= 1 with EmuTOS or TOS >= 2.06 only!)
|
||||
.TP
|
||||
.B \-\-cpuclock <x>
|
||||
Set the CPU clock (8, 16 or 32 Mhz)
|
||||
.TP
|
||||
.B \-\-compatible <bool>
|
||||
Use a more compatible, but slower 68000 CPU mode with
|
||||
better prefetch accuracy and cycle counting
|
||||
|
||||
.SH "Misc system options"
|
||||
.TP
|
||||
.B \-\-machine <x>
|
||||
Select machine type (x = st, ste, tt or falcon)
|
||||
.TP
|
||||
.B \-\-blitter <bool>
|
||||
Enable blitter emulation (ST only)
|
||||
.TP
|
||||
.B \-\-dsp <x>
|
||||
Falcon DSP emulation (x = none, dummy or emu, Falcon only)
|
||||
.TP
|
||||
.B \-\-timer\-d <bool>
|
||||
Patch redundantly high Timer-D frequency set by TOS. This about doubles
|
||||
Hatari speed (for ST/e emulation) as the original Timer-D frequency causes
|
||||
most of the interrupts.
|
||||
.TP
|
||||
.B \-\-fast\-boot <bool>
|
||||
Patch TOS and initialize the so-called "memvalid" system variables to by-pass
|
||||
the memory test of TOS, so that the system boots faster.
|
||||
.TP
|
||||
.B \-\-rtc <bool>
|
||||
Enable real-time clock
|
||||
|
||||
.SH "Sound options"
|
||||
.TP
|
||||
.B \-\-mic <bool>
|
||||
Enable/disable (Falcon only) microphone
|
||||
.TP
|
||||
.B \-\-sound <x>
|
||||
Sound frequency: 6000-50066. "off" disables the sound and speeds up
|
||||
the emulation. To prevent extra sound artifacts, the frequency should be
|
||||
selected so that it either matches evenly with the STE/TT/Falcon sound
|
||||
DMA (6258, 12517, 250033, 50066 Hz) or your sound card frequencies
|
||||
(11025, 22050, 44100 or 6000...48000 Hz). Check what your sound card
|
||||
supports.
|
||||
.TP
|
||||
.B \-\-sound\-buffer\-size <x>
|
||||
SDL's sound buffer size: 10-100, or 0 to use default buffer size.
|
||||
By default Hatari uses an SDL buffer size of 1024 samples, which
|
||||
gives approximatively 20-30 ms of sound depending on the chosen sound
|
||||
frequency. Under some OS or with not fully supported sound card, this
|
||||
default setting can cause a bigger delay at lower frequency (nearly 0.5 sec).
|
||||
In that case, you can use this option to force the size of the sound
|
||||
buffer to a fixed number of milliseconds of sound (using 20 is often
|
||||
a good choice if you have such problems). Most users will not need this option.
|
||||
.TP
|
||||
.B \-\-sound\-sync <bool>
|
||||
The emulation rate is nudged by +100 or 0 or \-100 micro-seconds on occasion.
|
||||
This prevents the sound buffer from overflowing (long latency and
|
||||
lost samples) or underflowing (short latency and repeated samples).
|
||||
The emulation rate smoothly deviates by a maximum of 0.58% until
|
||||
synchronized, while the emulator continuously generates every sound
|
||||
sample and the crystal controlled sound system consumes every sample.
|
||||
.br
|
||||
(on|off, off=default)
|
||||
.TP
|
||||
.B \-\-ym\-mixing <x>
|
||||
Select a method for mixing the three YM2149 voice volumes together.
|
||||
"model" uses a mathematical model of the YM voices,
|
||||
"table" uses a lookup table of audio output voltage values measured
|
||||
on STF and "linear" just averages the 3 YM voices.
|
||||
|
||||
.SH "Debug options"
|
||||
.TP
|
||||
.B \-W, \-\-wincon
|
||||
Open console window (Windows only)
|
||||
.TP
|
||||
.B \-D, \-\-debug
|
||||
Toggle whether CPU exceptions invoke the debugger
|
||||
.TP
|
||||
.B \-\-debug\-except <flags>
|
||||
Specify which exceptions invoke debugger, see
|
||||
.B \-\-debug\-except help
|
||||
for available (comma separated) exception flags.
|
||||
.TP
|
||||
.B \-\-bios\-intercept
|
||||
Toggle XBios command parsing. Allows Atari programs to use all Hatari
|
||||
functionality and change Hatari state through Hatari specifit
|
||||
XBios(255) calls. XBios(20) printscreen calls produce also Hatari
|
||||
screenshots.
|
||||
.TP
|
||||
.B \-\-conout <device>
|
||||
Enable console (xconout vector functions) output redirection for given
|
||||
<device> to host terminal. Device 2 is for the (CON:) VT52 console,
|
||||
which vector function catches also EmuTOS panic messages and MiNT
|
||||
console output, not just normal BIOS console output.
|
||||
.TP
|
||||
.B \-\-disasm <x>
|
||||
Set disassembly options. 'uae' and 'ext' select the dissasembly engine
|
||||
to use, bitmask sets output options for the external disassembly engine
|
||||
and 'help' lists them.
|
||||
.TP
|
||||
.B \-\-natfeats <bool>
|
||||
Enable/disable (basic) Native Features support.
|
||||
E.g. EmuTOS uses it for debug output.
|
||||
.TP
|
||||
.B \-\-trace <flags>
|
||||
Activate debug traces, see
|
||||
.B \-\-trace help
|
||||
for available (comma separated) tracing flags
|
||||
.TP
|
||||
.B \-\-trace\-file <file>
|
||||
Save trace output to <file> (default=stderr)
|
||||
.TP
|
||||
.B \-\-parse <file>
|
||||
Parse/execute debugger commands from <file>
|
||||
.TP
|
||||
.B \-\-saveconfig
|
||||
Save Hatari configuration and exit. Hatari UI needs Hatari configuration
|
||||
file to start, this can be used to create it automatically.
|
||||
.TP
|
||||
.B \-\-no\-parachute
|
||||
Disable SDL parachute to get Hatari core dumps. SDL parachute is enabled
|
||||
by default to restore video mode in case Hatari terminates abnormally
|
||||
while using non-standard screen resolution.
|
||||
.TP
|
||||
.B \-\-control\-socket <file>
|
||||
Hatari reads options from given socket at run-time
|
||||
.TP
|
||||
.B \-\-log\-file <file>
|
||||
Save log output to <file> (default=stderr)
|
||||
.TP
|
||||
.B \-\-log\-level <x>
|
||||
Log output level (x=debug/todo/info/warn/error/fatal)
|
||||
.TP
|
||||
.B \-\-alert\-level <x>
|
||||
Show dialog for log messages above given level
|
||||
.TP
|
||||
.B \-\-run\-vbls <x>
|
||||
Exit after X VBLs
|
||||
|
||||
.SH "INPUT HANDLING"
|
||||
Hatari provides special input handling for different purposes.
|
||||
|
||||
.SH "Emulated Atari ST joystick"
|
||||
Joystick can be emulated either with keyboard or any real joystick
|
||||
supported by your kernel / SDL library. First joystick button
|
||||
acts as FIRE, second as SPACE key.
|
||||
|
||||
.SH "Emulated Atari ST mouse"
|
||||
Middle button mouse click is interpreted as double click, this
|
||||
is especially useful in Fast Forward mode.
|
||||
.PP
|
||||
Mouse scrollwheel will act as cursor up and down keys.
|
||||
|
||||
.SH "Emulated Atari ST keyboard"
|
||||
Keys on the keyboard act as the normal Atari ST keys so pressing SPACE
|
||||
on your PC will result in an emulated press of the SPACE key on the
|
||||
ST. How the PC keys are mapped to Atari key codes, can be changed
|
||||
with keyboard config file (-k option).
|
||||
.PP
|
||||
The following keys have special meanings:
|
||||
.TP
|
||||
.B Alt
|
||||
will act as the ST's ALTERNATE key
|
||||
.TP
|
||||
.B left Ctrl
|
||||
will act as the ST's CONTROL key
|
||||
.TP
|
||||
.B Page Up
|
||||
will emulate the ST's HELP key
|
||||
.TP
|
||||
.B Page Down
|
||||
will emulate the ST's UNDO key
|
||||
.PP
|
||||
.B AltGr
|
||||
will act as
|
||||
.B Alternate
|
||||
as well as long as you do not press it together with a Hatari hotkey
|
||||
combination.
|
||||
.PP
|
||||
The
|
||||
.B right Ctrl
|
||||
key is used as the fire button of the emulated joystick when you turn
|
||||
on joystick emulation via keyboard.
|
||||
.PP
|
||||
The cursor keys will act as the cursor keys on the Atari ST as long as
|
||||
joystick emulation via keyboard has been turned off.
|
||||
|
||||
.SH "Keyboard shortcuts during emulation"
|
||||
The shortcut keys can be configured in the configuration file.
|
||||
The default settings are:
|
||||
.TP
|
||||
.B AltGr + a
|
||||
record animation
|
||||
.TP
|
||||
.B AltGr + g
|
||||
grab a screenshot
|
||||
.TP
|
||||
.B AltGr + i
|
||||
boss key: leave full screen mode and iconify window
|
||||
.TP
|
||||
.B AltGr + m
|
||||
(un-)lock the mouse into the window
|
||||
.TP
|
||||
.B AltGr + r
|
||||
warm reset the ST (same as the reset button)
|
||||
.TP
|
||||
.B AltGr + c
|
||||
cold reset the ST (same as the power switch)
|
||||
.TP
|
||||
.B AltGr + d
|
||||
open dialog to select/change disk A
|
||||
.TP
|
||||
.B AltGr + s
|
||||
enable/disable sound
|
||||
.TP
|
||||
.B AltGr + q
|
||||
quit the emulator
|
||||
.TP
|
||||
.B AltGr + x
|
||||
toggle normal/max speed
|
||||
.TP
|
||||
.B AltGr + y
|
||||
enable/disable sound recording
|
||||
.TP
|
||||
.B AltGr + k
|
||||
save memory snapshot
|
||||
.TP
|
||||
.B AltGr + l
|
||||
load memory snapshot
|
||||
.TP
|
||||
.B AltGr + j
|
||||
toggle joystick emulation via cursor keys
|
||||
.TP
|
||||
.B AltGr + F1
|
||||
switch joystick type on joy port 0
|
||||
.TP
|
||||
.B AltGr + F2
|
||||
switch joystick type on joy port 1
|
||||
.TP
|
||||
.B AltGr + F3
|
||||
switch joystick type for joypad A
|
||||
.TP
|
||||
.B AltGr + F4
|
||||
switch joystick type for joypad B
|
||||
.TP
|
||||
.B F11
|
||||
toggle between fullscreen and windowed mode
|
||||
.TP
|
||||
.B F12
|
||||
activate the hatari options GUI
|
||||
.br
|
||||
You may need to hold SHIFT down while in windowed mode.
|
||||
.TP
|
||||
.B Pause
|
||||
Pauses the emulation
|
||||
.TP
|
||||
.B AltGr + Pause
|
||||
Invokes the internal Hatari debugger
|
||||
|
||||
.SH "Keyboard shortcuts for the SDL GUI"
|
||||
There are multiple ways to interact with the SDL GUI.
|
||||
.PP
|
||||
TAB and cursor keys change focus between UI elements. Additionally
|
||||
Home key moves focus to first item, End key to last one. Initially
|
||||
focus is on default UI element, but focus changes are remembered
|
||||
between dialog invocations. Enter and Space invoke focused item. UI
|
||||
elements with underlined characters can be invoked directly with Alt +
|
||||
key with that character. Alt + arrow keys will act on arrow buttons.
|
||||
.PP
|
||||
Most importantly:
|
||||
.TP
|
||||
.B Options GUI main view
|
||||
Enter accepts configuration, ESC cancels it.
|
||||
.TP
|
||||
.B Options GUI dialogs
|
||||
Enter (or End+Enter if focus was moved) returns back to main view.
|
||||
.TP
|
||||
.B Fileselector
|
||||
Page up and down keys scroll the file list. Enter on focused file
|
||||
name selects it. Enter on OK button accepts the selected file. ESC
|
||||
cancels the dialog/selection.
|
||||
.TP
|
||||
.B Alert dialogs
|
||||
Enter accepts and ESC cancels the dialog.
|
||||
|
||||
.SH "SEE ALSO"
|
||||
The main program documentation, usually in /usr/share/doc/.
|
||||
Among other things it contains an extensive usage manual,
|
||||
software compatibility list and release notes.
|
||||
.PP
|
||||
The homepage of hatari: http://hatari.tuxfamily.org/
|
||||
.PP
|
||||
Other Hatari programs and utilities:
|
||||
.br
|
||||
.IR hmsa (1),
|
||||
.IR zip2st (1),
|
||||
.IR atari\-convert\-dir (1),
|
||||
.IR atari\-hd\-image (1),
|
||||
.IR hatariui (1),
|
||||
.IR hconsole (1),
|
||||
.IR gst2ascii (1),
|
||||
.IR hatari_profile (1)
|
||||
|
||||
.SH "FILES AND DIRECTORIES"
|
||||
.TP
|
||||
/etc/hatari.cfg (or /usr/local/etc/hatari.cfg)
|
||||
The global configuration file of Hatari.
|
||||
.TP
|
||||
~/.hatari/
|
||||
The (default) directory for user's personal Hatari files;
|
||||
.B hatari.cfg
|
||||
(configuration file),
|
||||
.B hatari.nvram
|
||||
(NVRAM content file),
|
||||
.B hatari.sav
|
||||
(Hatari memory state snapshot file which Hatari can load/save automatically
|
||||
when it starts/exits),
|
||||
.B hatari.prn
|
||||
(printer output file),
|
||||
.B hatari.wav
|
||||
(recorded sound output in WAV format),
|
||||
.B hatari.ym
|
||||
(recorded sound output in YM format).
|
||||
.TP
|
||||
/usr/share/hatari/ (or /usr/local/share/hatari/)
|
||||
The global data directory of Hatari.
|
||||
.TP
|
||||
tos.img
|
||||
The TOS ROM image will be loaded from the data directory of Hatari unless it
|
||||
is specified on the command line or the configuration file.
|
||||
|
||||
.SH "AUTHOR"
|
||||
This manual page was written by Marco Herrn <marco@mherrn.de> for the
|
||||
Debian project and later modified by Thomas Huth and Eero Tamminen to
|
||||
suit the latest version of Hatari.
|
BIN
doc/images/callgraph.png
Normal file
After Width: | Height: | Size: 21 KiB |
715
doc/images/callgraph.svg
Normal file
@ -0,0 +1,715 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 2.26.3 (20100126.1600)
|
||||
-->
|
||||
<!-- Title: profile Pages: 1 -->
|
||||
<svg width="842pt" height="595pt"
|
||||
viewBox="314.28 72.00 527.72 523.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph1" class="graph" transform="scale(0.137082 0.137082) rotate(0) translate(2296.65 3811.23)">
|
||||
<title>profile</title>
|
||||
<polygon fill="white" stroke="white" points="-4,5 -4,-3286 1554,-3286 1554,5 -4,5"/>
|
||||
<text text-anchor="middle" x="774.5" y="-3265.4" font-family="Times Roman,serif" font-size="14.00">Executed instructions</text>
|
||||
<text text-anchor="middle" x="774.5" y="-3247.4" font-family="Times Roman,serif" font-size="14.00">for badmood-1-frame-CPU.txt</text>
|
||||
<text text-anchor="middle" x="774.5" y="-3229.4" font-family="Times Roman,serif" font-size="14.00">(Hatari v1.6.2+ (May  4 2013), WinUAE CPU core)</text>
|
||||
<text text-anchor="middle" x="774.5" y="-3195.4" font-family="Times Roman,serif" font-size="14.00">own cost emphasis (gray bg) & total cost emphasis (red) limit = 2.00%</text>
|
||||
<text text-anchor="middle" x="774.5" y="-3177.4" font-family="Times Roman,serif" font-size="14.00">nodes which are subroutines and have accurate total costs, have diamond shape</text>
|
||||
<text text-anchor="middle" x="774.5" y="-3159.4" font-family="Times Roman,serif" font-size="14.00">24 leaf and/or intermediate nodes below 0.20% were removed</text>
|
||||
<!-- N_48100 -->
|
||||
<g id="node1" class="node"><title>N_48100</title>
|
||||
<polygon fill="none" stroke="red" stroke-width="2" points="844,-2742 710,-2644 844,-2546 978,-2644 844,-2742"/>
|
||||
<text text-anchor="middle" x="844" y="-2676.4" font-family="Times Roman,serif" font-size="14.00">4.30%</text>
|
||||
<text text-anchor="middle" x="844" y="-2658.4" font-family="Times Roman,serif" font-size="14.00">(own: 0.25%)</text>
|
||||
<text text-anchor="middle" x="844" y="-2640.4" font-family="Times Roman,serif" font-size="14.00">5819</text>
|
||||
<text text-anchor="middle" x="844" y="-2622.4" font-family="Times Roman,serif" font-size="14.00">visplane_tryflush</text>
|
||||
<text text-anchor="middle" x="844" y="-2604.4" font-family="Times Roman,serif" font-size="14.00">(15 calls)</text>
|
||||
</g>
|
||||
<!-- N_480B2 -->
|
||||
<g id="node12" class="node"><title>N_480B2</title>
|
||||
<polygon fill="none" stroke="red" stroke-width="2" points="927,-2438 807,-2340 927,-2242 1047,-2340 927,-2438"/>
|
||||
<text text-anchor="middle" x="927" y="-2372.4" font-family="Times Roman,serif" font-size="14.00">4.05%</text>
|
||||
<text text-anchor="middle" x="927" y="-2354.4" font-family="Times Roman,serif" font-size="14.00">(own: 0.05%)</text>
|
||||
<text text-anchor="middle" x="927" y="-2336.4" font-family="Times Roman,serif" font-size="14.00">5486</text>
|
||||
<text text-anchor="middle" x="927" y="-2318.4" font-family="Times Roman,serif" font-size="14.00">flush_visplanes</text>
|
||||
<text text-anchor="middle" x="927" y="-2300.4" font-family="Times Roman,serif" font-size="14.00">(7 calls)</text>
|
||||
</g>
|
||||
<!-- N_48100->N_480B2 -->
|
||||
<g id="edge64" class="edge"><title>N_48100->N_480B2</title>
|
||||
<path fill="none" stroke="red" stroke-width="2" d="M866.352,-2562.13C876.664,-2524.36 888.998,-2479.19 899.841,-2439.47"/>
|
||||
<polygon fill="red" stroke="red" points="906.596,-2441.31 905.111,-2420.17 893.091,-2437.62 906.596,-2441.31"/>
|
||||
<text text-anchor="middle" x="967" y="-2497.4" font-family="Times Roman,serif" font-size="14.00">visplane_tryflush+86</text>
|
||||
<text text-anchor="middle" x="967" y="-2479.4" font-family="Times Roman,serif" font-size="14.00">($48156)</text>
|
||||
</g>
|
||||
<!-- N_48780 -->
|
||||
<g id="node2" class="node"><title>N_48780</title>
|
||||
<ellipse fill="none" stroke="black" cx="748" cy="-57" rx="125.865" ry="56.5685"/>
|
||||
<text text-anchor="middle" x="748" y="-80.4" font-family="Times Roman,serif" font-size="14.00">0.98%</text>
|
||||
<text text-anchor="middle" x="748" y="-62.4" font-family="Times Roman,serif" font-size="14.00">1326</text>
|
||||
<text text-anchor="middle" x="748" y="-44.4" font-family="Times Roman,serif" font-size="14.00">R_BSPHyperPlane_RHS</text>
|
||||
<text text-anchor="middle" x="748" y="-26.4" font-family="Times Roman,serif" font-size="14.00">(587 calls)</text>
|
||||
</g>
|
||||
<!-- N_48780->N_48780 -->
|
||||
<g id="edge26" class="edge"><title>N_48780->N_48780</title>
|
||||
<path fill="none" stroke="black" d="M867.729,-74.8442C882.389,-71.6492 892,-65.7012 892,-57 892,-51.9696 888.788,-47.8594 883.245,-44.6694"/>
|
||||
<ellipse fill="black" stroke="black" cx="875.267" cy="-41.8346" rx="8.00001" ry="8.00001"/>
|
||||
<text text-anchor="middle" x="983.5" y="-80.4" font-family="Times Roman,serif" font-size="14.00">R_BSPHyperPlane_RHS+4</text>
|
||||
<text text-anchor="middle" x="983.5" y="-62.4" font-family="Times Roman,serif" font-size="14.00">($48784)</text>
|
||||
<text text-anchor="middle" x="983.5" y="-44.4" font-family="Times Roman,serif" font-size="14.00">567 calls</text>
|
||||
<text text-anchor="middle" x="983.5" y="-26.4" font-family="Times Roman,serif" font-size="14.00">=96.59%</text>
|
||||
</g>
|
||||
<!-- N_48728 -->
|
||||
<g id="node8" class="node"><title>N_48728</title>
|
||||
<ellipse fill="none" stroke="black" cx="419" cy="-588" rx="85.7684" ry="56.5685"/>
|
||||
<text text-anchor="middle" x="419" y="-611.4" font-family="Times Roman,serif" font-size="14.00">0.03%</text>
|
||||
<text text-anchor="middle" x="419" y="-593.4" font-family="Times Roman,serif" font-size="14.00">46</text>
|
||||
<text text-anchor="middle" x="419" y="-575.4" font-family="Times Roman,serif" font-size="14.00">R_PopBSPNode</text>
|
||||
<text text-anchor="middle" x="419" y="-557.4" font-family="Times Roman,serif" font-size="14.00">(23 calls)</text>
|
||||
</g>
|
||||
<!-- N_48780->N_48728 -->
|
||||
<g id="edge98" class="edge"><title>N_48780->N_48728</title>
|
||||
<path fill="none" stroke="black" d="M818.547,-104.367C826.395,-112.63 833.255,-121.87 838,-132 851.573,-160.979 859.381,-180.191 838,-204 813.061,-231.772 701.515,-200.504 671,-222 570.084,-293.089 624.549,-373.612 550,-472 532.594,-494.973 510.096,-516.851 488.671,-535.29"/>
|
||||
<ellipse fill="black" stroke="black" cx="482.355" cy="-540.59" rx="8.00002" ry="8.00002"/>
|
||||
<text text-anchor="middle" x="767" y="-325.4" font-family="Times Roman,serif" font-size="14.00">R_BSPHyperPlane_RHS+18</text>
|
||||
<text text-anchor="middle" x="767" y="-307.4" font-family="Times Roman,serif" font-size="14.00">($48792)</text>
|
||||
<text text-anchor="middle" x="767" y="-289.4" font-family="Times Roman,serif" font-size="14.00">3 calls</text>
|
||||
<text text-anchor="middle" x="767" y="-271.4" font-family="Times Roman,serif" font-size="14.00">=13.04%</text>
|
||||
</g>
|
||||
<!-- N_4872E -->
|
||||
<g id="node11" class="node"><title>N_4872E</title>
|
||||
<ellipse fill="lightgray" stroke="red" cx="419" cy="-302" rx="99.201" ry="56.5685"/>
|
||||
<text text-anchor="middle" x="419" y="-325.4" font-family="Times Roman,serif" font-size="14.00">3.82%</text>
|
||||
<text text-anchor="middle" x="419" y="-307.4" font-family="Times Roman,serif" font-size="14.00">5170</text>
|
||||
<text text-anchor="middle" x="419" y="-289.4" font-family="Times Roman,serif" font-size="14.00">R_BSPHyperPlane</text>
|
||||
<text text-anchor="middle" x="419" y="-271.4" font-family="Times Roman,serif" font-size="14.00">(36 calls)</text>
|
||||
</g>
|
||||
<!-- N_48780->N_4872E -->
|
||||
<g id="edge14" class="edge"><title>N_48780->N_4872E</title>
|
||||
<path fill="none" stroke="red" stroke-width="2" d="M673.714,-102.737C663.386,-111.48 653.695,-121.289 646,-132 626.4,-159.282 645.052,-178.658 623,-204 596.708,-234.215 559.009,-255.906 523.156,-271.07"/>
|
||||
<ellipse fill="red" stroke="red" cx="515.366" cy="-274.196" rx="8.00001" ry="8.00001"/>
|
||||
<text text-anchor="middle" x="742" y="-191.4" font-family="Times Roman,serif" font-size="14.00">R_BSPHyperPlane_RHS+24</text>
|
||||
<text text-anchor="middle" x="742" y="-173.4" font-family="Times Roman,serif" font-size="14.00">($48798)</text>
|
||||
<text text-anchor="middle" x="742" y="-155.4" font-family="Times Roman,serif" font-size="14.00">11 calls</text>
|
||||
<text text-anchor="middle" x="742" y="-137.4" font-family="Times Roman,serif" font-size="14.00">=30.56%</text>
|
||||
</g>
|
||||
<!-- N_481F8 -->
|
||||
<g id="node31" class="node"><title>N_481F8</title>
|
||||
<ellipse fill="none" stroke="black" cx="86" cy="-3093" rx="75.1594" ry="56.5685"/>
|
||||
<text text-anchor="middle" x="86" y="-3116.4" font-family="Times Roman,serif" font-size="14.00">0.06%</text>
|
||||
<text text-anchor="middle" x="86" y="-3098.4" font-family="Times Roman,serif" font-size="14.00">77</text>
|
||||
<text text-anchor="middle" x="86" y="-3080.4" font-family="Times Roman,serif" font-size="14.00">ssector_node</text>
|
||||
<text text-anchor="middle" x="86" y="-3062.4" font-family="Times Roman,serif" font-size="14.00">(16 calls)</text>
|
||||
</g>
|
||||
<!-- N_48780->N_481F8 -->
|
||||
<g id="edge28" class="edge"><title>N_48780->N_481F8</title>
|
||||
<path fill="none" stroke="black" d="M831.03,-99.7083C842.137,-108.884 852.068,-119.622 859,-132 886.149,-180.478 886.016,-331.429 863,-382 777.79,-569.226 687.127,-574.907 514,-686 415.897,-748.951 341.882,-698.533 275,-794 211.063,-885.263 256,-932.568 256,-1044 256,-1464 256,-1464 256,-1464 256,-1548.18 244.173,-1568.57 233,-1652 225.012,-1711.65 234.437,-1875.43 194,-1920 171.548,-1944.75 143.385,-1913.19 121,-1938 45.8411,-2021.3 86,-2075.81 86,-2188 86,-2907 86,-2907 86,-2907 86,-2944.32 86,-2985.86 86,-3020.2"/>
|
||||
<ellipse fill="black" stroke="black" cx="86" cy="-3028.43" rx="8" ry="8"/>
|
||||
<text text-anchor="middle" x="341" y="-1639.4" font-family="Times Roman,serif" font-size="14.00">R_BSPHyperPlane_RHS+26</text>
|
||||
<text text-anchor="middle" x="341" y="-1621.4" font-family="Times Roman,serif" font-size="14.00">($4879a)</text>
|
||||
<text text-anchor="middle" x="341" y="-1603.4" font-family="Times Roman,serif" font-size="14.00">6 calls</text>
|
||||
<text text-anchor="middle" x="341" y="-1585.4" font-family="Times Roman,serif" font-size="14.00">=37.50%</text>
|
||||
</g>
|
||||
<!-- N_48206 -->
|
||||
<g id="node3" class="node"><title>N_48206</title>
|
||||
<ellipse fill="none" stroke="black" cx="448" cy="-2907" rx="74.9533" ry="56.5685"/>
|
||||
<text text-anchor="middle" x="448" y="-2930.4" font-family="Times Roman,serif" font-size="14.00">0.41%</text>
|
||||
<text text-anchor="middle" x="448" y="-2912.4" font-family="Times Roman,serif" font-size="14.00">550</text>
|
||||
<text text-anchor="middle" x="448" y="-2894.4" font-family="Times Roman,serif" font-size="14.00">build_ssector</text>
|
||||
<text text-anchor="middle" x="448" y="-2876.4" font-family="Times Roman,serif" font-size="14.00">(15 calls)</text>
|
||||
</g>
|
||||
<!-- N_48206->N_48100 -->
|
||||
<g id="edge34" class="edge"><title>N_48206->N_48100</title>
|
||||
<path fill="none" stroke="red" stroke-width="2" d="M521.844,-2896.22C573.251,-2886.02 641.539,-2866.87 693,-2832 732.192,-2805.44 766.224,-2765.66 792.008,-2729.52"/>
|
||||
<polygon fill="red" stroke="red" points="798.024,-2733.13 803.625,-2712.69 786.503,-2725.17 798.024,-2733.13"/>
|
||||
<text text-anchor="middle" x="829.5" y="-2801.4" font-family="Times Roman,serif" font-size="14.00">build_ssector+116</text>
|
||||
<text text-anchor="middle" x="829.5" y="-2783.4" font-family="Times Roman,serif" font-size="14.00">($4827a)</text>
|
||||
</g>
|
||||
<!-- N_482A0 -->
|
||||
<g id="node7" class="node"><title>N_482A0</title>
|
||||
<ellipse fill="lightgray" stroke="red" cx="336" cy="-2644" rx="79.196" ry="56.5685"/>
|
||||
<text text-anchor="middle" x="336" y="-2667.4" font-family="Times Roman,serif" font-size="14.00">2.04%</text>
|
||||
<text text-anchor="middle" x="336" y="-2649.4" font-family="Times Roman,serif" font-size="14.00">2766</text>
|
||||
<text text-anchor="middle" x="336" y="-2631.4" font-family="Times Roman,serif" font-size="14.00">segment_loop</text>
|
||||
<text text-anchor="middle" x="336" y="-2613.4" font-family="Times Roman,serif" font-size="14.00">(50 calls)</text>
|
||||
</g>
|
||||
<!-- N_48206->N_482A0 -->
|
||||
<g id="edge68" class="edge"><title>N_48206->N_482A0</title>
|
||||
<path fill="none" stroke="red" stroke-width="2" d="M419.781,-2854.5C416.026,-2847.01 412.328,-2839.35 409,-2832 391.648,-2793.65 374.495,-2749.87 361.181,-2714.2"/>
|
||||
<ellipse fill="red" stroke="red" cx="358.312" cy="-2706.45" rx="8.00001" ry="8.00001"/>
|
||||
<text text-anchor="middle" x="473.5" y="-2819.4" font-family="Times Roman,serif" font-size="14.00">build_ssector+150</text>
|
||||
<text text-anchor="middle" x="473.5" y="-2801.4" font-family="Times Roman,serif" font-size="14.00">($4829c)</text>
|
||||
<text text-anchor="middle" x="473.5" y="-2783.4" font-family="Times Roman,serif" font-size="14.00">15 calls</text>
|
||||
<text text-anchor="middle" x="473.5" y="-2765.4" font-family="Times Roman,serif" font-size="14.00">=30.00%</text>
|
||||
</g>
|
||||
<!-- N_4A3E8 -->
|
||||
<g id="node26" class="node"><title>N_4A3E8</title>
|
||||
<polygon fill="none" stroke="black" points="560,-2724 433,-2644 560,-2564 687,-2644 560,-2724"/>
|
||||
<text text-anchor="middle" x="560" y="-2667.4" font-family="Times Roman,serif" font-size="14.00">0.47%</text>
|
||||
<text text-anchor="middle" x="560" y="-2649.4" font-family="Times Roman,serif" font-size="14.00">630</text>
|
||||
<text text-anchor="middle" x="560" y="-2631.4" font-family="Times Roman,serif" font-size="14.00">process_lighting</text>
|
||||
<text text-anchor="middle" x="560" y="-2613.4" font-family="Times Roman,serif" font-size="14.00">(15 calls)</text>
|
||||
</g>
|
||||
<!-- N_48206->N_4A3E8 -->
|
||||
<g id="edge96" class="edge"><title>N_48206->N_4A3E8</title>
|
||||
<path fill="none" stroke="black" d="M505.674,-2870.08C518.265,-2859.32 530.156,-2846.49 538,-2832 552.691,-2804.87 559.565,-2772.35 562.38,-2742.05"/>
|
||||
<polygon fill="black" stroke="black" points="569.369,-2742.45 563.706,-2722.03 555.4,-2741.52 569.369,-2742.45"/>
|
||||
<text text-anchor="middle" x="624.5" y="-2801.4" font-family="Times Roman,serif" font-size="14.00">build_ssector+112</text>
|
||||
<text text-anchor="middle" x="624.5" y="-2783.4" font-family="Times Roman,serif" font-size="14.00">($48276)</text>
|
||||
</g>
|
||||
<!-- N_48716 -->
|
||||
<g id="node4" class="node"><title>N_48716</title>
|
||||
<ellipse fill="none" stroke="black" cx="755" cy="-892" rx="103.238" ry="56.5685"/>
|
||||
<text text-anchor="middle" x="755" y="-915.4" font-family="Times Roman,serif" font-size="14.00">0.07%</text>
|
||||
<text text-anchor="middle" x="755" y="-897.4" font-family="Times Roman,serif" font-size="14.00">96</text>
|
||||
<text text-anchor="middle" x="755" y="-879.4" font-family="Times Roman,serif" font-size="14.00">R_RenderBSPNode</text>
|
||||
<text text-anchor="middle" x="755" y="-861.4" font-family="Times Roman,serif" font-size="14.00">(16 calls)</text>
|
||||
</g>
|
||||
<!-- N_48716->N_48728 -->
|
||||
<g id="edge30" class="edge"><title>N_48716->N_48728</title>
|
||||
<path fill="none" stroke="black" d="M701.388,-843.494C641.636,-789.433 545.12,-702.108 481.86,-644.873"/>
|
||||
<ellipse fill="black" stroke="black" cx="475.604" cy="-639.213" rx="8.00002" ry="8.00002"/>
|
||||
<text text-anchor="middle" x="698" y="-763.4" font-family="Times Roman,serif" font-size="14.00">R_RenderBSPNode+16</text>
|
||||
<text text-anchor="middle" x="698" y="-745.4" font-family="Times Roman,serif" font-size="14.00">($48726)</text>
|
||||
<text text-anchor="middle" x="698" y="-727.4" font-family="Times Roman,serif" font-size="14.00">16 calls</text>
|
||||
<text text-anchor="middle" x="698" y="-709.4" font-family="Times Roman,serif" font-size="14.00">=69.57%</text>
|
||||
</g>
|
||||
<!-- N_4819C -->
|
||||
<g id="node5" class="node"><title>N_4819C</title>
|
||||
<ellipse fill="none" stroke="black" cx="1320" cy="-2340" rx="62.9325" ry="56.5685"/>
|
||||
<text text-anchor="middle" x="1320" y="-2363.4" font-family="Times Roman,serif" font-size="14.00">0.01%</text>
|
||||
<text text-anchor="middle" x="1320" y="-2345.4" font-family="Times Roman,serif" font-size="14.00">20</text>
|
||||
<text text-anchor="middle" x="1320" y="-2327.4" font-family="Times Roman,serif" font-size="14.00">finish_tree</text>
|
||||
<text text-anchor="middle" x="1320" y="-2309.4" font-family="Times Roman,serif" font-size="14.00">(1 calls)</text>
|
||||
</g>
|
||||
<!-- N_48BDC -->
|
||||
<g id="node9" class="node"><title>N_48BDC</title>
|
||||
<polygon fill="none" stroke="black" points="1180,-2134 1069,-2036 1180,-1938 1291,-2036 1180,-2134"/>
|
||||
<text text-anchor="middle" x="1180" y="-2068.4" font-family="Times Roman,serif" font-size="14.00">0.63%</text>
|
||||
<text text-anchor="middle" x="1180" y="-2050.4" font-family="Times Roman,serif" font-size="14.00">(own: 0.05%)</text>
|
||||
<text text-anchor="middle" x="1180" y="-2032.4" font-family="Times Roman,serif" font-size="14.00">857</text>
|
||||
<text text-anchor="middle" x="1180" y="-2014.4" font-family="Times Roman,serif" font-size="14.00">get_flat_floor</text>
|
||||
<text text-anchor="middle" x="1180" y="-1996.4" font-family="Times Roman,serif" font-size="14.00">(2 calls)</text>
|
||||
</g>
|
||||
<!-- N_4819C->N_48BDC -->
|
||||
<g id="edge56" class="edge"><title>N_4819C->N_48BDC</title>
|
||||
<path fill="none" stroke="black" d="M1317.49,-2283.23C1314.68,-2236.5 1308.98,-2174.43 1298,-2152 1287.69,-2130.95 1271.97,-2111.53 1255.33,-2094.84"/>
|
||||
<polygon fill="black" stroke="black" points="1259.93,-2089.56 1240.58,-2080.91 1250.31,-2099.73 1259.93,-2089.56"/>
|
||||
<text text-anchor="middle" x="1363.5" y="-2211.4" font-family="Times Roman,serif" font-size="14.00">finish_tree+64</text>
|
||||
<text text-anchor="middle" x="1363.5" y="-2193.4" font-family="Times Roman,serif" font-size="14.00">($481dc)</text>
|
||||
<text text-anchor="middle" x="1363.5" y="-2175.4" font-family="Times Roman,serif" font-size="14.00">1 calls</text>
|
||||
<text text-anchor="middle" x="1363.5" y="-2157.4" font-family="Times Roman,serif" font-size="14.00">=50.00%</text>
|
||||
</g>
|
||||
<!-- N_48B74 -->
|
||||
<g id="node15" class="node"><title>N_48B74</title>
|
||||
<polygon fill="none" stroke="black" points="1429,-2134 1309,-2036 1429,-1938 1549,-2036 1429,-2134"/>
|
||||
<text text-anchor="middle" x="1429" y="-2068.4" font-family="Times Roman,serif" font-size="14.00">0.35%</text>
|
||||
<text text-anchor="middle" x="1429" y="-2050.4" font-family="Times Roman,serif" font-size="14.00">(own: 0.08%)</text>
|
||||
<text text-anchor="middle" x="1429" y="-2032.4" font-family="Times Roman,serif" font-size="14.00">470</text>
|
||||
<text text-anchor="middle" x="1429" y="-2014.4" font-family="Times Roman,serif" font-size="14.00">get_flat_ceiling</text>
|
||||
<text text-anchor="middle" x="1429" y="-1996.4" font-family="Times Roman,serif" font-size="14.00">(3 calls)</text>
|
||||
</g>
|
||||
<!-- N_4819C->N_48B74 -->
|
||||
<g id="edge52" class="edge"><title>N_4819C->N_48B74</title>
|
||||
<path fill="none" stroke="black" d="M1366.98,-2301.85C1388.59,-2281.3 1412.05,-2254.03 1424,-2224 1433.62,-2199.82 1437.74,-2172.48 1438.84,-2146.29"/>
|
||||
<polygon fill="black" stroke="black" points="1445.84,-2146.18 1439.14,-2126.08 1431.85,-2145.98 1445.84,-2146.18"/>
|
||||
<text text-anchor="middle" x="1489.5" y="-2211.4" font-family="Times Roman,serif" font-size="14.00">finish_tree+40</text>
|
||||
<text text-anchor="middle" x="1489.5" y="-2193.4" font-family="Times Roman,serif" font-size="14.00">($481c4)</text>
|
||||
<text text-anchor="middle" x="1489.5" y="-2175.4" font-family="Times Roman,serif" font-size="14.00">1 calls</text>
|
||||
<text text-anchor="middle" x="1489.5" y="-2157.4" font-family="Times Roman,serif" font-size="14.00">=33.33%</text>
|
||||
</g>
|
||||
<!-- N_4879E -->
|
||||
<g id="node6" class="node"><title>N_4879E</title>
|
||||
<ellipse fill="none" stroke="black" cx="124" cy="-57" rx="123.951" ry="56.5685"/>
|
||||
<text text-anchor="middle" x="124" y="-80.4" font-family="Times Roman,serif" font-size="14.00">0.75%</text>
|
||||
<text text-anchor="middle" x="124" y="-62.4" font-family="Times Roman,serif" font-size="14.00">1015</text>
|
||||
<text text-anchor="middle" x="124" y="-44.4" font-family="Times Roman,serif" font-size="14.00">R_BSPHyperPlane_LHS</text>
|
||||
<text text-anchor="middle" x="124" y="-26.4" font-family="Times Roman,serif" font-size="14.00">(449 calls)</text>
|
||||
</g>
|
||||
<!-- N_4879E->N_4879E -->
|
||||
<g id="edge62" class="edge"><title>N_4879E->N_4879E</title>
|
||||
<path fill="none" stroke="black" d="M241.798,-74.9031C256.405,-71.7226 266,-65.7549 266,-57 266,-51.9386 262.793,-47.8087 257.265,-44.6104"/>
|
||||
<ellipse fill="black" stroke="black" cx="249.333" cy="-41.7831" rx="8.00001" ry="8.00001"/>
|
||||
<text text-anchor="middle" x="356.5" y="-80.4" font-family="Times Roman,serif" font-size="14.00">R_BSPHyperPlane_LHS+4</text>
|
||||
<text text-anchor="middle" x="356.5" y="-62.4" font-family="Times Roman,serif" font-size="14.00">($487a2)</text>
|
||||
<text text-anchor="middle" x="356.5" y="-44.4" font-family="Times Roman,serif" font-size="14.00">433 calls</text>
|
||||
<text text-anchor="middle" x="356.5" y="-26.4" font-family="Times Roman,serif" font-size="14.00">=96.44%</text>
|
||||
</g>
|
||||
<!-- N_4879E->N_48728 -->
|
||||
<g id="edge54" class="edge"><title>N_4879E->N_48728</title>
|
||||
<path fill="none" stroke="black" d="M73.2152,-108.58C68.2543,-115.973 63.9683,-123.851 61,-132 21.8903,-239.365 52.2545,-290.726 121,-382 176.875,-456.185 267.44,-513.327 334.086,-548.406"/>
|
||||
<ellipse fill="black" stroke="black" cx="341.238" cy="-552.099" rx="8.00002" ry="8.00002"/>
|
||||
<text text-anchor="middle" x="216" y="-325.4" font-family="Times Roman,serif" font-size="14.00">R_BSPHyperPlane_LHS+18</text>
|
||||
<text text-anchor="middle" x="216" y="-307.4" font-family="Times Roman,serif" font-size="14.00">($487b0)</text>
|
||||
<text text-anchor="middle" x="216" y="-289.4" font-family="Times Roman,serif" font-size="14.00">4 calls</text>
|
||||
<text text-anchor="middle" x="216" y="-271.4" font-family="Times Roman,serif" font-size="14.00">=17.39%</text>
|
||||
</g>
|
||||
<!-- N_4879E->N_4872E -->
|
||||
<g id="edge32" class="edge"><title>N_4879E->N_4872E</title>
|
||||
<path fill="none" stroke="red" stroke-width="2" d="M201.571,-101.325C212.915,-110.351 223.588,-120.618 232,-132 251.967,-159.015 234.121,-177.683 255,-204 273.437,-227.239 299.009,-246.202 324.48,-261.04"/>
|
||||
<ellipse fill="red" stroke="red" cx="331.579" cy="-264.979" rx="8.00002" ry="8.00002"/>
|
||||
<text text-anchor="middle" x="350" y="-191.4" font-family="Times Roman,serif" font-size="14.00">R_BSPHyperPlane_LHS+26</text>
|
||||
<text text-anchor="middle" x="350" y="-173.4" font-family="Times Roman,serif" font-size="14.00">($487b8)</text>
|
||||
<text text-anchor="middle" x="350" y="-155.4" font-family="Times Roman,serif" font-size="14.00">8 calls</text>
|
||||
<text text-anchor="middle" x="350" y="-137.4" font-family="Times Roman,serif" font-size="14.00">=22.22%</text>
|
||||
</g>
|
||||
<!-- N_4879E->N_481F8 -->
|
||||
<g id="edge74" class="edge"><title>N_4879E->N_481F8</title>
|
||||
<path fill="none" stroke="black" d="M60.061,-105.628C52.6545,-113.701 45.9821,-122.551 41,-132 5.43875,-199.443 18,-225.756 18,-302 18,-1464 18,-1464 18,-1464 18,-1515.57 15.8788,-1528.43 15,-1580 10.3955,-1850.19 10,-1917.77 10,-2188 10,-2907 10,-2907 10,-2907 10,-2949.27 27.0314,-2993.21 44.9692,-3027.75"/>
|
||||
<ellipse fill="black" stroke="black" cx="48.8531" cy="-3034.92" rx="8.00002" ry="8.00002"/>
|
||||
<text text-anchor="middle" x="110" y="-1639.4" font-family="Times Roman,serif" font-size="14.00">R_BSPHyperPlane_LHS+30</text>
|
||||
<text text-anchor="middle" x="110" y="-1621.4" font-family="Times Roman,serif" font-size="14.00">($487bc)</text>
|
||||
<text text-anchor="middle" x="110" y="-1603.4" font-family="Times Roman,serif" font-size="14.00">4 calls</text>
|
||||
<text text-anchor="middle" x="110" y="-1585.4" font-family="Times Roman,serif" font-size="14.00">=25.00%</text>
|
||||
</g>
|
||||
<!-- N_483BA -->
|
||||
<g id="node16" class="node"><title>N_483BA</title>
|
||||
<ellipse fill="none" stroke="black" cx="466" cy="-2340" rx="99.9096" ry="56.5685"/>
|
||||
<text text-anchor="middle" x="466" y="-2363.4" font-family="Times Roman,serif" font-size="14.00">0.26%</text>
|
||||
<text text-anchor="middle" x="466" y="-2345.4" font-family="Times Roman,serif" font-size="14.00">357</text>
|
||||
<text text-anchor="middle" x="466" y="-2327.4" font-family="Times Roman,serif" font-size="14.00">seg_prelight_done</text>
|
||||
<text text-anchor="middle" x="466" y="-2309.4" font-family="Times Roman,serif" font-size="14.00">(21 calls)</text>
|
||||
</g>
|
||||
<!-- N_482A0->N_483BA -->
|
||||
<g id="edge44" class="edge"><title>N_482A0->N_483BA</title>
|
||||
<path fill="none" stroke="black" d="M372.952,-2593.79C387.379,-2576.84 405.019,-2558.96 424,-2546 442.818,-2533.16 459.022,-2546.73 472,-2528 495.111,-2494.65 494.375,-2449.39 487.496,-2411.63"/>
|
||||
<ellipse fill="black" stroke="black" cx="485.859" cy="-2403.8" rx="8.00001" ry="8.00001"/>
|
||||
<text text-anchor="middle" x="562" y="-2515.4" font-family="Times Roman,serif" font-size="14.00">segment_loop+-498</text>
|
||||
<text text-anchor="middle" x="562" y="-2497.4" font-family="Times Roman,serif" font-size="14.00">($480ae)</text>
|
||||
<text text-anchor="middle" x="562" y="-2479.4" font-family="Times Roman,serif" font-size="14.00">1 calls</text>
|
||||
<text text-anchor="middle" x="562" y="-2461.4" font-family="Times Roman,serif" font-size="14.00">=4.76%</text>
|
||||
</g>
|
||||
<!-- N_482A0->N_483BA -->
|
||||
<g id="edge58" class="edge"><title>N_482A0->N_483BA</title>
|
||||
<path fill="none" stroke="black" d="M322.923,-2587.97C316.716,-2549.18 314.218,-2497.3 333,-2456 344.344,-2431.05 363.997,-2409.38 384.767,-2391.73"/>
|
||||
<ellipse fill="black" stroke="black" cx="391.192" cy="-2386.56" rx="8.00002" ry="8.00002"/>
|
||||
<text text-anchor="middle" x="400.5" y="-2515.4" font-family="Times Roman,serif" font-size="14.00">segment_loop+278</text>
|
||||
<text text-anchor="middle" x="400.5" y="-2497.4" font-family="Times Roman,serif" font-size="14.00">($483b6)</text>
|
||||
<text text-anchor="middle" x="400.5" y="-2479.4" font-family="Times Roman,serif" font-size="14.00">20 calls</text>
|
||||
<text text-anchor="middle" x="400.5" y="-2461.4" font-family="Times Roman,serif" font-size="14.00">=95.24%</text>
|
||||
</g>
|
||||
<!-- N_486CC -->
|
||||
<g id="node18" class="node"><title>N_486CC</title>
|
||||
<ellipse fill="none" stroke="black" cx="579" cy="-1750" rx="85.0596" ry="56.5685"/>
|
||||
<text text-anchor="middle" x="579" y="-1773.4" font-family="Times Roman,serif" font-size="14.00">0.03%</text>
|
||||
<text text-anchor="middle" x="579" y="-1755.4" font-family="Times Roman,serif" font-size="14.00">36</text>
|
||||
<text text-anchor="middle" x="579" y="-1737.4" font-family="Times Roman,serif" font-size="14.00">sector_window</text>
|
||||
<text text-anchor="middle" x="579" y="-1719.4" font-family="Times Roman,serif" font-size="14.00">(36 calls)</text>
|
||||
</g>
|
||||
<!-- N_482A0->N_486CC -->
|
||||
<g id="edge46" class="edge"><title>N_482A0->N_486CC</title>
|
||||
<path fill="none" stroke="black" d="M369.714,-2592.59C384.196,-2574.76 402.711,-2556.6 424,-2546 466.326,-2524.93 601.03,-2559.82 636,-2528 761.604,-2413.71 587.181,-2275.26 704,-2152 727.878,-2126.81 758.468,-2161.23 780,-2134 834.035,-2065.67 814.676,-2017.91 780,-1938 754.553,-1879.36 700.803,-1830.66 655.285,-1797.53"/>
|
||||
<ellipse fill="black" stroke="black" cx="648.61" cy="-1792.8" rx="8.00002" ry="8.00002"/>
|
||||
<text text-anchor="middle" x="771.5" y="-2211.4" font-family="Times Roman,serif" font-size="14.00">segment_loop+248</text>
|
||||
<text text-anchor="middle" x="771.5" y="-2193.4" font-family="Times Roman,serif" font-size="14.00">($48398)</text>
|
||||
<text text-anchor="middle" x="771.5" y="-2175.4" font-family="Times Roman,serif" font-size="14.00">15 calls</text>
|
||||
<text text-anchor="middle" x="771.5" y="-2157.4" font-family="Times Roman,serif" font-size="14.00">=41.67%</text>
|
||||
</g>
|
||||
<!-- N_486D0 -->
|
||||
<g id="node20" class="node"><title>N_486D0</title>
|
||||
<ellipse fill="none" stroke="black" cx="476" cy="-1464" rx="72.832" ry="56.5685"/>
|
||||
<text text-anchor="middle" x="476" y="-1487.4" font-family="Times Roman,serif" font-size="14.00">0.20%</text>
|
||||
<text text-anchor="middle" x="476" y="-1469.4" font-family="Times Roman,serif" font-size="14.00">270</text>
|
||||
<text text-anchor="middle" x="476" y="-1451.4" font-family="Times Roman,serif" font-size="14.00">seg_invisible</text>
|
||||
<text text-anchor="middle" x="476" y="-1433.4" font-family="Times Roman,serif" font-size="14.00">(50 calls)</text>
|
||||
</g>
|
||||
<!-- N_482A0->N_486D0 -->
|
||||
<g id="edge70" class="edge"><title>N_482A0->N_486D0</title>
|
||||
<path fill="none" stroke="black" d="M310.202,-2590.56C241.361,-2444.35 63.9685,-2041.73 146,-1938 167.532,-1910.77 192.602,-1938.46 222,-1920 343.215,-1843.89 321.863,-1769.24 425,-1670 434.608,-1660.76 442.202,-1663.47 449,-1652 469.336,-1617.68 476.482,-1573.82 478.362,-1537.09"/>
|
||||
<ellipse fill="black" stroke="black" cx="478.628" cy="-1528.78" rx="8" ry="8"/>
|
||||
<text text-anchor="middle" x="213.5" y="-2059.4" font-family="Times Roman,serif" font-size="14.00">segment_loop+118</text>
|
||||
<text text-anchor="middle" x="213.5" y="-2041.4" font-family="Times Roman,serif" font-size="14.00">($48316)</text>
|
||||
<text text-anchor="middle" x="213.5" y="-2023.4" font-family="Times Roman,serif" font-size="14.00">14 calls</text>
|
||||
<text text-anchor="middle" x="213.5" y="-2005.4" font-family="Times Roman,serif" font-size="14.00">=28.00%</text>
|
||||
</g>
|
||||
<!-- N_48728->N_4872E -->
|
||||
<g id="edge92" class="edge"><title>N_48728->N_4872E</title>
|
||||
<path fill="none" stroke="red" stroke-width="2" d="M419,-531.496C419,-486.692 419,-423.743 419,-375.103"/>
|
||||
<ellipse fill="red" stroke="red" cx="419" cy="-366.876" rx="8" ry="8"/>
|
||||
<text text-anchor="middle" x="482.5" y="-459.4" font-family="Times Roman,serif" font-size="14.00">R_PopBSPNode+2</text>
|
||||
<text text-anchor="middle" x="482.5" y="-441.4" font-family="Times Roman,serif" font-size="14.00">($4872a)</text>
|
||||
<text text-anchor="middle" x="482.5" y="-423.4" font-family="Times Roman,serif" font-size="14.00">17 calls</text>
|
||||
<text text-anchor="middle" x="482.5" y="-405.4" font-family="Times Roman,serif" font-size="14.00">=47.22%</text>
|
||||
</g>
|
||||
<!-- N_48728->N_481F8 -->
|
||||
<g id="edge38" class="edge"><title>N_48728->N_481F8</title>
|
||||
<path fill="none" stroke="black" d="M365.136,-632.418C305.597,-686.837 218,-785.072 218,-892 218,-1330 218,-1330 218,-1330 218,-1473.17 255.048,-1516.44 209,-1652 174.401,-1753.85 103.015,-1746.64 67,-1848 16.3282,-1990.61 48,-2036.65 48,-2188 48,-2907 48,-2907 48,-2907 48,-2945.55 55.9339,-2987.71 64.5512,-3022.12"/>
|
||||
<ellipse fill="black" stroke="black" cx="66.6417" cy="-3030.11" rx="8.00001" ry="8.00001"/>
|
||||
<text text-anchor="middle" x="130.5" y="-1907.4" font-family="Times Roman,serif" font-size="14.00">R_PopBSPNode+2</text>
|
||||
<text text-anchor="middle" x="130.5" y="-1889.4" font-family="Times Roman,serif" font-size="14.00">($4872a)</text>
|
||||
<text text-anchor="middle" x="130.5" y="-1871.4" font-family="Times Roman,serif" font-size="14.00">6 calls</text>
|
||||
<text text-anchor="middle" x="130.5" y="-1853.4" font-family="Times Roman,serif" font-size="14.00">=37.50%</text>
|
||||
</g>
|
||||
<!-- N_48C74 -->
|
||||
<g id="node30" class="node"><title>N_48C74</title>
|
||||
<polygon fill="lightgray" stroke="red" points="1180,-1830 1025,-1750 1180,-1670 1335,-1750 1180,-1830"/>
|
||||
<text text-anchor="middle" x="1180" y="-1773.4" font-family="Times Roman,serif" font-size="14.00">2.41%</text>
|
||||
<text text-anchor="middle" x="1180" y="-1755.4" font-family="Times Roman,serif" font-size="14.00">3264</text>
|
||||
<text text-anchor="middle" x="1180" y="-1737.4" font-family="Times Roman,serif" font-size="14.00">stack_visplane_area</text>
|
||||
<text text-anchor="middle" x="1180" y="-1719.4" font-family="Times Roman,serif" font-size="14.00">(13 calls)</text>
|
||||
</g>
|
||||
<!-- N_48BDC->N_48C74 -->
|
||||
<g id="edge78" class="edge"><title>N_48BDC->N_48C74</title>
|
||||
<path fill="none" stroke="red" stroke-width="2" d="M1180,-1937.98C1180,-1909.74 1180,-1878.9 1180,-1850.51"/>
|
||||
<polygon fill="red" stroke="red" points="1187,-1850.35 1180,-1830.35 1173,-1850.35 1187,-1850.35"/>
|
||||
<text text-anchor="middle" x="1240.5" y="-1907.4" font-family="Times Roman,serif" font-size="14.00">get_flat_floor+90</text>
|
||||
<text text-anchor="middle" x="1240.5" y="-1889.4" font-family="Times Roman,serif" font-size="14.00">($48c36)</text>
|
||||
<text text-anchor="middle" x="1240.5" y="-1871.4" font-family="Times Roman,serif" font-size="14.00">2 calls</text>
|
||||
<text text-anchor="middle" x="1240.5" y="-1853.4" font-family="Times Roman,serif" font-size="14.00">=15.38%</text>
|
||||
</g>
|
||||
<!-- N_49C2C -->
|
||||
<g id="node10" class="node"><title>N_49C2C</title>
|
||||
<ellipse fill="lightgray" stroke="red" cx="998" cy="-302" rx="92.839" ry="56.5685"/>
|
||||
<text text-anchor="middle" x="998" y="-325.4" font-family="Times Roman,serif" font-size="14.00">39.97%</text>
|
||||
<text text-anchor="middle" x="998" y="-307.4" font-family="Times Roman,serif" font-size="14.00">54144</text>
|
||||
<text text-anchor="middle" x="998" y="-289.4" font-family="Times Roman,serif" font-size="14.00">render_wall_1x1</text>
|
||||
<text text-anchor="middle" x="998" y="-271.4" font-family="Times Roman,serif" font-size="14.00">(18 calls)</text>
|
||||
</g>
|
||||
<!-- N_4872E->N_48780 -->
|
||||
<g id="edge94" class="edge"><title>N_4872E->N_48780</title>
|
||||
<path fill="none" stroke="black" d="M433.862,-246.033C437.508,-232.289 441.398,-217.613 445,-204 453.466,-172.006 440.6,-155.404 464,-132 485.896,-110.1 550.943,-92.098 613.266,-79.2254"/>
|
||||
<ellipse fill="black" stroke="black" cx="621.18" cy="-77.6376" rx="8.00001" ry="8.00001"/>
|
||||
<text text-anchor="middle" x="541.5" y="-191.4" font-family="Times Roman,serif" font-size="14.00">R_BSPHyperPlane+80</text>
|
||||
<text text-anchor="middle" x="541.5" y="-173.4" font-family="Times Roman,serif" font-size="14.00">($4877e)</text>
|
||||
<text text-anchor="middle" x="541.5" y="-155.4" font-family="Times Roman,serif" font-size="14.00">20 calls</text>
|
||||
<text text-anchor="middle" x="541.5" y="-137.4" font-family="Times Roman,serif" font-size="14.00">=3.41%</text>
|
||||
</g>
|
||||
<!-- N_4872E->N_4879E -->
|
||||
<g id="edge8" class="edge"><title>N_4872E->N_4879E</title>
|
||||
<path fill="none" stroke="black" d="M350.304,-261.002C322.551,-246.292 289.645,-231.104 258,-222 219.155,-210.824 104.131,-233.963 77,-204 57.3349,-182.282 63.0443,-152.298 76.0392,-125.071"/>
|
||||
<ellipse fill="black" stroke="black" cx="79.8992" cy="-117.79" rx="8.00002" ry="8.00002"/>
|
||||
<text text-anchor="middle" x="154.5" y="-191.4" font-family="Times Roman,serif" font-size="14.00">R_BSPHyperPlane+80</text>
|
||||
<text text-anchor="middle" x="154.5" y="-173.4" font-family="Times Roman,serif" font-size="14.00">($4877e)</text>
|
||||
<text text-anchor="middle" x="154.5" y="-155.4" font-family="Times Roman,serif" font-size="14.00">16 calls</text>
|
||||
<text text-anchor="middle" x="154.5" y="-137.4" font-family="Times Roman,serif" font-size="14.00">=3.56%</text>
|
||||
</g>
|
||||
<!-- N_480B2->N_48BDC -->
|
||||
<g id="edge100" class="edge"><title>N_480B2->N_48BDC</title>
|
||||
<path fill="none" stroke="black" d="M962.908,-2271.14C970.315,-2255.81 977.753,-2239.51 984,-2224 996.553,-2192.84 983.463,-2175.97 1007,-2152 1024.43,-2134.25 1038.24,-2146.06 1060,-2134 1077.29,-2124.42 1094.53,-2112.26 1110.34,-2099.8"/>
|
||||
<polygon fill="black" stroke="black" points="1115.19,-2104.88 1126.24,-2086.8 1106.33,-2094.05 1115.19,-2104.88"/>
|
||||
<text text-anchor="middle" x="1074" y="-2211.4" font-family="Times Roman,serif" font-size="14.00">flush_visplanes+42</text>
|
||||
<text text-anchor="middle" x="1074" y="-2193.4" font-family="Times Roman,serif" font-size="14.00">($480dc)</text>
|
||||
<text text-anchor="middle" x="1074" y="-2175.4" font-family="Times Roman,serif" font-size="14.00">1 calls</text>
|
||||
<text text-anchor="middle" x="1074" y="-2157.4" font-family="Times Roman,serif" font-size="14.00">=50.00%</text>
|
||||
</g>
|
||||
<!-- N_480B2->N_48B74 -->
|
||||
<g id="edge50" class="edge"><title>N_480B2->N_48B74</title>
|
||||
<path fill="none" stroke="black" d="M1013.19,-2312.15C1057.4,-2293.71 1108.62,-2265.2 1141,-2224 1161.45,-2197.98 1135.13,-2173.83 1160,-2152 1207.15,-2110.62 1241.95,-2157.78 1300,-2134 1319.92,-2125.84 1339.47,-2113.8 1357.08,-2100.92"/>
|
||||
<polygon fill="black" stroke="black" points="1361.4,-2106.43 1372.99,-2088.69 1352.86,-2095.33 1361.4,-2106.43"/>
|
||||
<text text-anchor="middle" x="1227" y="-2211.4" font-family="Times Roman,serif" font-size="14.00">flush_visplanes+62</text>
|
||||
<text text-anchor="middle" x="1227" y="-2193.4" font-family="Times Roman,serif" font-size="14.00">($480f0)</text>
|
||||
<text text-anchor="middle" x="1227" y="-2175.4" font-family="Times Roman,serif" font-size="14.00">2 calls</text>
|
||||
<text text-anchor="middle" x="1227" y="-2157.4" font-family="Times Roman,serif" font-size="14.00">=66.67%</text>
|
||||
</g>
|
||||
<!-- N_48B00 -->
|
||||
<g id="node23" class="node"><title>N_48B00</title>
|
||||
<polygon fill="none" stroke="red" stroke-width="2" points="940,-2134 829,-2036 940,-1938 1051,-2036 940,-2134"/>
|
||||
<text text-anchor="middle" x="940" y="-2068.4" font-family="Times Roman,serif" font-size="14.00">3.25%</text>
|
||||
<text text-anchor="middle" x="940" y="-2050.4" font-family="Times Roman,serif" font-size="14.00">(own: 1.69%)</text>
|
||||
<text text-anchor="middle" x="940" y="-2032.4" font-family="Times Roman,serif" font-size="14.00">4401</text>
|
||||
<text text-anchor="middle" x="940" y="-2014.4" font-family="Times Roman,serif" font-size="14.00">get_ssector</text>
|
||||
<text text-anchor="middle" x="940" y="-1996.4" font-family="Times Roman,serif" font-size="14.00">(4 calls)</text>
|
||||
</g>
|
||||
<!-- N_480B2->N_48B00 -->
|
||||
<g id="edge4" class="edge"><title>N_480B2->N_48B00</title>
|
||||
<path fill="none" stroke="red" stroke-width="2" d="M878.576,-2281.41C866.913,-2263.98 856.074,-2244.13 850,-2224 840.757,-2193.36 839.633,-2182.27 850,-2152 855.76,-2135.18 865.062,-2118.91 875.549,-2104.15"/>
|
||||
<polygon fill="red" stroke="red" points="881.181,-2108.31 887.767,-2088.17 870.059,-2099.81 881.181,-2108.31"/>
|
||||
<text text-anchor="middle" x="917" y="-2193.4" font-family="Times Roman,serif" font-size="14.00">flush_visplanes+10</text>
|
||||
<text text-anchor="middle" x="917" y="-2175.4" font-family="Times Roman,serif" font-size="14.00">($480bc)</text>
|
||||
</g>
|
||||
<!-- N_494B4 -->
|
||||
<g id="node13" class="node"><title>N_494B4</title>
|
||||
<polygon fill="lightgray" stroke="red" points="1125,-1294 1005,-1196 1125,-1098 1245,-1196 1125,-1294"/>
|
||||
<text text-anchor="middle" x="1125" y="-1228.4" font-family="Times Roman,serif" font-size="14.00">34.82%</text>
|
||||
<text text-anchor="middle" x="1125" y="-1210.4" font-family="Times Roman,serif" font-size="14.00">(own: 27.62%)</text>
|
||||
<text text-anchor="middle" x="1125" y="-1192.4" font-family="Times Roman,serif" font-size="14.00">47161</text>
|
||||
<text text-anchor="middle" x="1125" y="-1174.4" font-family="Times Roman,serif" font-size="14.00">render_flats</text>
|
||||
<text text-anchor="middle" x="1125" y="-1156.4" font-family="Times Roman,serif" font-size="14.00">(1 calls)</text>
|
||||
</g>
|
||||
<!-- N_494CC -->
|
||||
<g id="node19" class="node"><title>N_494CC</title>
|
||||
<ellipse fill="lightgray" stroke="red" cx="1276" cy="-892" rx="94.0452" ry="56.5685"/>
|
||||
<text text-anchor="middle" x="1276" y="-915.4" font-family="Times Roman,serif" font-size="14.00">27.56%</text>
|
||||
<text text-anchor="middle" x="1276" y="-897.4" font-family="Times Roman,serif" font-size="14.00">37335</text>
|
||||
<text text-anchor="middle" x="1276" y="-879.4" font-family="Times Roman,serif" font-size="14.00">render_flats_1x1</text>
|
||||
<text text-anchor="middle" x="1276" y="-861.4" font-family="Times Roman,serif" font-size="14.00">(1 calls)</text>
|
||||
</g>
|
||||
<!-- N_494B4->N_494CC -->
|
||||
<g id="edge76" class="edge"><title>N_494B4->N_494CC</title>
|
||||
<path fill="none" stroke="red" stroke-width="2" d="M1159.64,-1126.26C1184.31,-1076.58 1217.32,-1010.14 1241.87,-960.707"/>
|
||||
<ellipse fill="red" stroke="red" cx="1245.48" cy="-953.437" rx="8.00002" ry="8.00002"/>
|
||||
<text text-anchor="middle" x="1270.5" y="-1049.4" font-family="Times Roman,serif" font-size="14.00">render_flats+20</text>
|
||||
<text text-anchor="middle" x="1270.5" y="-1031.4" font-family="Times Roman,serif" font-size="14.00">($494c8)</text>
|
||||
</g>
|
||||
<!-- N_47438 -->
|
||||
<g id="node14" class="node"><title>N_47438</title>
|
||||
<polygon fill="none" stroke="black" points="1277,-382 1155,-302 1277,-222 1399,-302 1277,-382"/>
|
||||
<text text-anchor="middle" x="1277" y="-325.4" font-family="Times Roman,serif" font-size="14.00">0.28%</text>
|
||||
<text text-anchor="middle" x="1277" y="-307.4" font-family="Times Roman,serif" font-size="14.00">378</text>
|
||||
<text text-anchor="middle" x="1277" y="-289.4" font-family="Times Roman,serif" font-size="14.00">cache_resource</text>
|
||||
<text text-anchor="middle" x="1277" y="-271.4" font-family="Times Roman,serif" font-size="14.00">(21 calls)</text>
|
||||
</g>
|
||||
<!-- N_48B74->N_48C74 -->
|
||||
<g id="edge16" class="edge"><title>N_48B74->N_48C74</title>
|
||||
<path fill="none" stroke="red" stroke-width="2" d="M1391.64,-1968.27C1369.18,-1930.71 1338.51,-1884.38 1305,-1848 1292.31,-1834.22 1277.55,-1820.86 1262.72,-1808.66"/>
|
||||
<polygon fill="red" stroke="red" points="1266.69,-1802.88 1246.68,-1795.91 1257.98,-1813.83 1266.69,-1802.88"/>
|
||||
<text text-anchor="middle" x="1425" y="-1907.4" font-family="Times Roman,serif" font-size="14.00">get_flat_ceiling+86</text>
|
||||
<text text-anchor="middle" x="1425" y="-1889.4" font-family="Times Roman,serif" font-size="14.00">($48bca)</text>
|
||||
<text text-anchor="middle" x="1425" y="-1871.4" font-family="Times Roman,serif" font-size="14.00">3 calls</text>
|
||||
<text text-anchor="middle" x="1425" y="-1853.4" font-family="Times Roman,serif" font-size="14.00">=23.08%</text>
|
||||
</g>
|
||||
<!-- N_483BA->N_486CC -->
|
||||
<g id="edge66" class="edge"><title>N_483BA->N_486CC</title>
|
||||
<path fill="none" stroke="black" d="M532.392,-2297.67C556.5,-2278.41 580.995,-2253.34 594,-2224 627.862,-2147.61 600.339,-1931.31 594,-1848 593.363,-1839.63 592.425,-1830.9 591.323,-1822.24"/>
|
||||
<ellipse fill="black" stroke="black" cx="590.215" cy="-1814.24" rx="8.00001" ry="8.00001"/>
|
||||
<text text-anchor="middle" x="693.5" y="-2059.4" font-family="Times Roman,serif" font-size="14.00">seg_prelight_done+456</text>
|
||||
<text text-anchor="middle" x="693.5" y="-2041.4" font-family="Times Roman,serif" font-size="14.00">($48582)</text>
|
||||
<text text-anchor="middle" x="693.5" y="-2023.4" font-family="Times Roman,serif" font-size="14.00">6 calls</text>
|
||||
<text text-anchor="middle" x="693.5" y="-2005.4" font-family="Times Roman,serif" font-size="14.00">=16.67%</text>
|
||||
</g>
|
||||
<!-- N_48650 -->
|
||||
<g id="node24" class="node"><title>N_48650</title>
|
||||
<ellipse fill="none" stroke="black" cx="505" cy="-2036" rx="67.1751" ry="56.5685"/>
|
||||
<text text-anchor="middle" x="505" y="-2059.4" font-family="Times Roman,serif" font-size="14.00">0.33%</text>
|
||||
<text text-anchor="middle" x="505" y="-2041.4" font-family="Times Roman,serif" font-size="14.00">450</text>
|
||||
<text text-anchor="middle" x="505" y="-2023.4" font-family="Times Roman,serif" font-size="14.00">sector_wall</text>
|
||||
<text text-anchor="middle" x="505" y="-2005.4" font-family="Times Roman,serif" font-size="14.00">(15 calls)</text>
|
||||
</g>
|
||||
<!-- N_483BA->N_48650 -->
|
||||
<g id="edge48" class="edge"><title>N_483BA->N_48650</title>
|
||||
<path fill="none" stroke="black" d="M446.004,-2284.62C435.202,-2246.81 426.253,-2195.83 438,-2152 442.961,-2133.49 451.67,-2114.88 461.2,-2098.15"/>
|
||||
<ellipse fill="black" stroke="black" cx="465.405" cy="-2091.14" rx="8.00002" ry="8.00002"/>
|
||||
<text text-anchor="middle" x="516" y="-2193.4" font-family="Times Roman,serif" font-size="14.00">seg_prelight_done+64</text>
|
||||
<text text-anchor="middle" x="516" y="-2175.4" font-family="Times Roman,serif" font-size="14.00">($483fa)</text>
|
||||
</g>
|
||||
<!-- N_48C44 -->
|
||||
<g id="node17" class="node"><title>N_48C44</title>
|
||||
<polygon fill="lightgray" stroke="red" points="859,-1276 731,-1196 859,-1116 987,-1196 859,-1276"/>
|
||||
<text text-anchor="middle" x="859" y="-1219.4" font-family="Times Roman,serif" font-size="14.00">2.28%</text>
|
||||
<text text-anchor="middle" x="859" y="-1201.4" font-family="Times Roman,serif" font-size="14.00">3086</text>
|
||||
<text text-anchor="middle" x="859" y="-1183.4" font-family="Times Roman,serif" font-size="14.00">init_stategroups</text>
|
||||
<text text-anchor="middle" x="859" y="-1165.4" font-family="Times Roman,serif" font-size="14.00">(1 calls)</text>
|
||||
</g>
|
||||
<!-- N_486CC->N_486D0 -->
|
||||
<g id="edge88" class="edge"><title>N_486CC->N_486D0</title>
|
||||
<path fill="none" stroke="black" d="M559.141,-1694.86C542.594,-1648.91 518.934,-1583.21 501.081,-1533.64"/>
|
||||
<ellipse fill="black" stroke="black" cx="498.334" cy="-1526.02" rx="8.00001" ry="8.00001"/>
|
||||
<text text-anchor="middle" x="595.5" y="-1630.4" font-family="Times Roman,serif" font-size="14.00">sector_window</text>
|
||||
<text text-anchor="middle" x="595.5" y="-1612.4" font-family="Times Roman,serif" font-size="14.00">36 calls</text>
|
||||
<text text-anchor="middle" x="595.5" y="-1594.4" font-family="Times Roman,serif" font-size="14.00">=72.00%</text>
|
||||
</g>
|
||||
<!-- N_494CC->N_47438 -->
|
||||
<g id="edge36" class="edge"><title>N_494CC->N_47438</title>
|
||||
<path fill="none" stroke="black" d="M1334.85,-847.532C1355.77,-828.13 1376.89,-803.513 1388,-776 1405.77,-732.003 1408.65,-611.309 1375,-490 1363.91,-450.014 1343.58,-408.786 1324.3,-375.165"/>
|
||||
<polygon fill="black" stroke="black" points="1330.26,-371.492 1314.07,-357.826 1318.2,-378.608 1330.26,-371.492"/>
|
||||
<text text-anchor="middle" x="1473.5" y="-611.4" font-family="Times Roman,serif" font-size="14.00">render_flats_1x1+62</text>
|
||||
<text text-anchor="middle" x="1473.5" y="-593.4" font-family="Times Roman,serif" font-size="14.00">($4950a)</text>
|
||||
<text text-anchor="middle" x="1473.5" y="-575.4" font-family="Times Roman,serif" font-size="14.00">3 calls</text>
|
||||
<text text-anchor="middle" x="1473.5" y="-557.4" font-family="Times Roman,serif" font-size="14.00">=14.29%</text>
|
||||
</g>
|
||||
<!-- N_49438 -->
|
||||
<g id="node21" class="node"><title>N_49438</title>
|
||||
<polygon fill="lightgray" stroke="red" points="1242,-668 1118,-588 1242,-508 1366,-588 1242,-668"/>
|
||||
<text text-anchor="middle" x="1242" y="-611.4" font-family="Times Roman,serif" font-size="14.00">7.16%</text>
|
||||
<text text-anchor="middle" x="1242" y="-593.4" font-family="Times Roman,serif" font-size="14.00">9701</text>
|
||||
<text text-anchor="middle" x="1242" y="-575.4" font-family="Times Roman,serif" font-size="14.00">stream_texture</text>
|
||||
<text text-anchor="middle" x="1242" y="-557.4" font-family="Times Roman,serif" font-size="14.00">(3 calls)</text>
|
||||
</g>
|
||||
<!-- N_494CC->N_49438 -->
|
||||
<g id="edge40" class="edge"><title>N_494CC->N_49438</title>
|
||||
<path fill="none" stroke="red" stroke-width="2" d="M1255.71,-836.702C1249.73,-817.729 1243.98,-796.186 1241,-776 1236.67,-746.627 1235.54,-714.391 1235.88,-685.035"/>
|
||||
<polygon fill="red" stroke="red" points="1242.89,-684.906 1236.36,-664.749 1228.89,-684.581 1242.89,-684.906"/>
|
||||
<text text-anchor="middle" x="1314.5" y="-745.4" font-family="Times Roman,serif" font-size="14.00">render_flats_1x1+66</text>
|
||||
<text text-anchor="middle" x="1314.5" y="-727.4" font-family="Times Roman,serif" font-size="14.00">($4950e)</text>
|
||||
</g>
|
||||
<!-- N_486D0->N_482A0 -->
|
||||
<g id="edge90" class="edge"><title>N_486D0->N_482A0</title>
|
||||
<path fill="none" stroke="red" stroke-width="2" d="M481.942,-1520.34C484.341,-1558.12 484.467,-1608.69 474,-1652 453.221,-1737.97 429.639,-1753.64 385,-1830 355.76,-1880.02 328.966,-1882.6 312,-1938 273.604,-2063.37 305.539,-2397.39 317,-2528 318.251,-2542.25 320.241,-2557.4 322.473,-2571.88"/>
|
||||
<ellipse fill="red" stroke="red" cx="323.786" cy="-2579.97" rx="8.00001" ry="8.00001"/>
|
||||
<text text-anchor="middle" x="370.5" y="-2059.4" font-family="Times Roman,serif" font-size="14.00">seg_invisible+18</text>
|
||||
<text text-anchor="middle" x="370.5" y="-2041.4" font-family="Times Roman,serif" font-size="14.00">($486e2)</text>
|
||||
<text text-anchor="middle" x="370.5" y="-2023.4" font-family="Times Roman,serif" font-size="14.00">35 calls</text>
|
||||
<text text-anchor="middle" x="370.5" y="-2005.4" font-family="Times Roman,serif" font-size="14.00">=70.00%</text>
|
||||
</g>
|
||||
<!-- N_486E6 -->
|
||||
<g id="node25" class="node"><title>N_486E6</title>
|
||||
<ellipse fill="none" stroke="black" cx="410" cy="-1196" rx="62.9325" ry="56.5685"/>
|
||||
<text text-anchor="middle" x="410" y="-1219.4" font-family="Times Roman,serif" font-size="14.00">0.21%</text>
|
||||
<text text-anchor="middle" x="410" y="-1201.4" font-family="Times Roman,serif" font-size="14.00">278</text>
|
||||
<text text-anchor="middle" x="410" y="-1183.4" font-family="Times Roman,serif" font-size="14.00">do_ssector</text>
|
||||
<text text-anchor="middle" x="410" y="-1165.4" font-family="Times Roman,serif" font-size="14.00">(15 calls)</text>
|
||||
</g>
|
||||
<!-- N_486D0->N_486E6 -->
|
||||
<g id="edge24" class="edge"><title>N_486D0->N_486E6</title>
|
||||
<path fill="none" stroke="black" d="M462.325,-1408.47C452.236,-1367.51 438.428,-1311.43 427.529,-1267.18"/>
|
||||
<ellipse fill="black" stroke="black" cx="425.571" cy="-1259.23" rx="8.00001" ry="8.00001"/>
|
||||
<text text-anchor="middle" x="505.5" y="-1335.4" font-family="Times Roman,serif" font-size="14.00">seg_invisible+12</text>
|
||||
<text text-anchor="middle" x="505.5" y="-1317.4" font-family="Times Roman,serif" font-size="14.00">($486dc)</text>
|
||||
</g>
|
||||
<!-- N_4815C -->
|
||||
<g id="node22" class="node"><title>N_4815C</title>
|
||||
<polygon fill="lightgray" stroke="red" points="602,-1294 491,-1196 602,-1098 713,-1196 602,-1294"/>
|
||||
<text text-anchor="middle" x="602" y="-1228.4" font-family="Times Roman,serif" font-size="14.00">59.72%</text>
|
||||
<text text-anchor="middle" x="602" y="-1210.4" font-family="Times Roman,serif" font-size="14.00">(own: 9.63%)</text>
|
||||
<text text-anchor="middle" x="602" y="-1192.4" font-family="Times Roman,serif" font-size="14.00">80888</text>
|
||||
<text text-anchor="middle" x="602" y="-1174.4" font-family="Times Roman,serif" font-size="14.00">descend_bsp</text>
|
||||
<text text-anchor="middle" x="602" y="-1156.4" font-family="Times Roman,serif" font-size="14.00">(1 calls)</text>
|
||||
</g>
|
||||
<!-- N_4815C->N_48716 -->
|
||||
<g id="edge20" class="edge"><title>N_4815C->N_48716</title>
|
||||
<path fill="none" stroke="black" d="M656.517,-1145.74C676.215,-1129.17 699.229,-1111.54 722,-1098 740.159,-1087.2 754.223,-1097.54 766,-1080 788.643,-1046.27 786.715,-1001 778.733,-963.33"/>
|
||||
<ellipse fill="black" stroke="black" cx="776.858" cy="-955.489" rx="8.00001" ry="8.00001"/>
|
||||
<text text-anchor="middle" x="843.5" y="-1067.4" font-family="Times Roman,serif" font-size="14.00">descend_bsp+60</text>
|
||||
<text text-anchor="middle" x="843.5" y="-1049.4" font-family="Times Roman,serif" font-size="14.00">($48198)</text>
|
||||
<text text-anchor="middle" x="843.5" y="-1031.4" font-family="Times Roman,serif" font-size="14.00">1 calls</text>
|
||||
<text text-anchor="middle" x="843.5" y="-1013.4" font-family="Times Roman,serif" font-size="14.00">=6.25%</text>
|
||||
</g>
|
||||
<!-- N_48B00->N_48C74 -->
|
||||
<g id="edge22" class="edge"><title>N_48B00->N_48C74</title>
|
||||
<path fill="none" stroke="red" stroke-width="2" d="M974.906,-1968.75C996.168,-1931.11 1025.46,-1884.56 1058,-1848 1070.01,-1834.51 1084.01,-1821.42 1098.15,-1809.42"/>
|
||||
<polygon fill="red" stroke="red" points="1103.04,-1814.47 1114.09,-1796.39 1094.17,-1803.63 1103.04,-1814.47"/>
|
||||
<text text-anchor="middle" x="1118" y="-1907.4" font-family="Times Roman,serif" font-size="14.00">get_ssector+100</text>
|
||||
<text text-anchor="middle" x="1118" y="-1889.4" font-family="Times Roman,serif" font-size="14.00">($48b64)</text>
|
||||
<text text-anchor="middle" x="1118" y="-1871.4" font-family="Times Roman,serif" font-size="14.00">8 calls</text>
|
||||
<text text-anchor="middle" x="1118" y="-1853.4" font-family="Times Roman,serif" font-size="14.00">=61.54%</text>
|
||||
</g>
|
||||
<!-- N_48650->N_486CC -->
|
||||
<g id="edge84" class="edge"><title>N_48650->N_486CC</title>
|
||||
<path fill="none" stroke="black" d="M481.732,-1982.59C468.384,-1943.85 457.582,-1890.95 476,-1848 483.299,-1830.98 495.166,-1815.52 508.296,-1802.17"/>
|
||||
<ellipse fill="black" stroke="black" cx="514.274" cy="-1796.49" rx="8.00002" ry="8.00002"/>
|
||||
<text text-anchor="middle" x="535" y="-1907.4" font-family="Times Roman,serif" font-size="14.00">sector_wall+120</text>
|
||||
<text text-anchor="middle" x="535" y="-1889.4" font-family="Times Roman,serif" font-size="14.00">($486c8)</text>
|
||||
<text text-anchor="middle" x="535" y="-1871.4" font-family="Times Roman,serif" font-size="14.00">15 calls</text>
|
||||
<text text-anchor="middle" x="535" y="-1853.4" font-family="Times Roman,serif" font-size="14.00">=41.67%</text>
|
||||
</g>
|
||||
<!-- N_486E6->N_48716 -->
|
||||
<g id="edge60" class="edge"><title>N_486E6->N_48716</title>
|
||||
<path fill="none" stroke="black" d="M440.369,-1146.27C452.04,-1129.65 466.353,-1111.86 482,-1098 494.216,-1087.18 503.691,-1092.65 514,-1080 535.222,-1053.96 511.632,-1030.02 537,-1008 573.086,-976.675 599.838,-1010.51 643,-990 662.248,-980.856 680.719,-967.431 696.915,-953.434"/>
|
||||
<ellipse fill="black" stroke="black" cx="702.893" cy="-948.04" rx="8.00002" ry="8.00002"/>
|
||||
<text text-anchor="middle" x="588.5" y="-1067.4" font-family="Times Roman,serif" font-size="14.00">do_ssector+46</text>
|
||||
<text text-anchor="middle" x="588.5" y="-1049.4" font-family="Times Roman,serif" font-size="14.00">($48714)</text>
|
||||
<text text-anchor="middle" x="588.5" y="-1031.4" font-family="Times Roman,serif" font-size="14.00">15 calls</text>
|
||||
<text text-anchor="middle" x="588.5" y="-1013.4" font-family="Times Roman,serif" font-size="14.00">=93.75%</text>
|
||||
</g>
|
||||
<!-- N_49B28 -->
|
||||
<g id="node29" class="node"><title>N_49B28</title>
|
||||
<polygon fill="none" stroke="red" stroke-width="2" points="1020,-990 876,-892 1020,-794 1164,-892 1020,-990"/>
|
||||
<text text-anchor="middle" x="1020" y="-924.4" font-family="Times Roman,serif" font-size="14.00">42.19%</text>
|
||||
<text text-anchor="middle" x="1020" y="-906.4" font-family="Times Roman,serif" font-size="14.00">(own: 1.70%)</text>
|
||||
<text text-anchor="middle" x="1020" y="-888.4" font-family="Times Roman,serif" font-size="14.00">57144</text>
|
||||
<text text-anchor="middle" x="1020" y="-870.4" font-family="Times Roman,serif" font-size="14.00">add_wall_segment</text>
|
||||
<text text-anchor="middle" x="1020" y="-852.4" font-family="Times Roman,serif" font-size="14.00">(18 calls)</text>
|
||||
</g>
|
||||
<!-- N_486E6->N_49B28 -->
|
||||
<g id="edge42" class="edge"><title>N_486E6->N_49B28</title>
|
||||
<path fill="none" stroke="red" stroke-width="2" d="M436.252,-1144.51C447.856,-1126.9 463.186,-1108.9 482,-1098 543.147,-1062.56 586.545,-1126.24 640,-1080 665.031,-1058.35 633.678,-1029.31 659,-1008 694.498,-978.127 823.078,-1004.95 867,-990 890.917,-981.861 914.844,-969.223 936.434,-955.697"/>
|
||||
<polygon fill="red" stroke="red" points="940.297,-961.535 953.203,-944.729 932.633,-949.819 940.297,-961.535"/>
|
||||
<text text-anchor="middle" x="710.5" y="-1049.4" font-family="Times Roman,serif" font-size="14.00">do_ssector+20</text>
|
||||
<text text-anchor="middle" x="710.5" y="-1031.4" font-family="Times Roman,serif" font-size="14.00">($486fa)</text>
|
||||
</g>
|
||||
<!-- N_49ACC -->
|
||||
<g id="node32" class="node"><title>N_49ACC</title>
|
||||
<polygon fill="lightgray" stroke="red" points="459,-972 284,-892 459,-812 634,-892 459,-972"/>
|
||||
<text text-anchor="middle" x="459" y="-915.4" font-family="Times Roman,serif" font-size="14.00">2.84%</text>
|
||||
<text text-anchor="middle" x="459" y="-897.4" font-family="Times Roman,serif" font-size="14.00">3851</text>
|
||||
<text text-anchor="middle" x="459" y="-879.4" font-family="Times Roman,serif" font-size="14.00">add_partition_segment</text>
|
||||
<text text-anchor="middle" x="459" y="-861.4" font-family="Times Roman,serif" font-size="14.00">(6 calls)</text>
|
||||
</g>
|
||||
<!-- N_486E6->N_49ACC -->
|
||||
<g id="edge72" class="edge"><title>N_486E6->N_49ACC</title>
|
||||
<path fill="none" stroke="red" stroke-width="2" d="M404.674,-1139.49C402.498,-1101.85 402.232,-1051.51 411,-1008 413.099,-997.583 416.14,-986.926 419.687,-976.498"/>
|
||||
<polygon fill="red" stroke="red" points="426.353,-978.657 426.769,-957.471 413.232,-973.773 426.353,-978.657"/>
|
||||
<text text-anchor="middle" x="462.5" y="-1049.4" font-family="Times Roman,serif" font-size="14.00">do_ssector+20</text>
|
||||
<text text-anchor="middle" x="462.5" y="-1031.4" font-family="Times Roman,serif" font-size="14.00">($486fa)</text>
|
||||
</g>
|
||||
<!-- N_49BEA -->
|
||||
<g id="node27" class="node"><title>N_49BEA</title>
|
||||
<polygon fill="lightgray" stroke="red" points="980,-686 860,-588 980,-490 1100,-588 980,-686"/>
|
||||
<text text-anchor="middle" x="980" y="-620.4" font-family="Times Roman,serif" font-size="14.00">40.49%</text>
|
||||
<text text-anchor="middle" x="980" y="-602.4" font-family="Times Roman,serif" font-size="14.00">(own: 40.25%)</text>
|
||||
<text text-anchor="middle" x="980" y="-584.4" font-family="Times Roman,serif" font-size="14.00">54844</text>
|
||||
<text text-anchor="middle" x="980" y="-566.4" font-family="Times Roman,serif" font-size="14.00">render_wall</text>
|
||||
<text text-anchor="middle" x="980" y="-548.4" font-family="Times Roman,serif" font-size="14.00">(18 calls)</text>
|
||||
</g>
|
||||
<!-- N_49BEA->N_49C2C -->
|
||||
<g id="edge82" class="edge"><title>N_49BEA->N_49C2C</title>
|
||||
<path fill="none" stroke="red" stroke-width="2" d="M985.869,-494.749C988.316,-455.875 991.115,-411.398 993.407,-374.971"/>
|
||||
<ellipse fill="red" stroke="red" cx="993.919" cy="-366.834" rx="8" ry="8"/>
|
||||
<text text-anchor="middle" x="1048" y="-441.4" font-family="Times Roman,serif" font-size="14.00">render_wall+62</text>
|
||||
<text text-anchor="middle" x="1048" y="-423.4" font-family="Times Roman,serif" font-size="14.00">($49c28)</text>
|
||||
</g>
|
||||
<!-- N_49BEA->N_47438 -->
|
||||
<g id="edge18" class="edge"><title>N_49BEA->N_47438</title>
|
||||
<path fill="none" stroke="black" d="M1037.61,-536.946C1059.84,-516.945 1085.33,-493.643 1108,-472 1144.12,-437.513 1183.51,-398.006 1215.17,-365.761"/>
|
||||
<polygon fill="black" stroke="black" points="1220.59,-370.225 1229.58,-351.037 1210.59,-360.431 1220.59,-370.225"/>
|
||||
<text text-anchor="middle" x="1234" y="-459.4" font-family="Times Roman,serif" font-size="14.00">render_wall+26</text>
|
||||
<text text-anchor="middle" x="1234" y="-441.4" font-family="Times Roman,serif" font-size="14.00">($49c04)</text>
|
||||
<text text-anchor="middle" x="1234" y="-423.4" font-family="Times Roman,serif" font-size="14.00">18 calls</text>
|
||||
<text text-anchor="middle" x="1234" y="-405.4" font-family="Times Roman,serif" font-size="14.00">=85.71%</text>
|
||||
</g>
|
||||
<!-- N_47A6C -->
|
||||
<g id="node28" class="node"><title>N_47A6C</title>
|
||||
<polygon fill="none" stroke="red" stroke-width="2" points="992,-1562 874,-1464 992,-1366 1110,-1464 992,-1562"/>
|
||||
<text text-anchor="middle" x="992" y="-1496.4" font-family="Times Roman,serif" font-size="14.00">100.00%</text>
|
||||
<text text-anchor="middle" x="992" y="-1478.4" font-family="Times Roman,serif" font-size="14.00">(own: 0.09%)</text>
|
||||
<text text-anchor="middle" x="992" y="-1460.4" font-family="Times Roman,serif" font-size="14.00">135449</text>
|
||||
<text text-anchor="middle" x="992" y="-1442.4" font-family="Times Roman,serif" font-size="14.00">display_engine</text>
|
||||
<text text-anchor="middle" x="992" y="-1424.4" font-family="Times Roman,serif" font-size="14.00">(1 calls)</text>
|
||||
</g>
|
||||
<!-- N_47A6C->N_494B4 -->
|
||||
<g id="edge6" class="edge"><title>N_47A6C->N_494B4</title>
|
||||
<path fill="none" stroke="red" stroke-width="2" d="M1026.6,-1394.29C1043.31,-1360.61 1063.55,-1319.83 1081.31,-1284.03"/>
|
||||
<polygon fill="red" stroke="red" points="1087.72,-1286.86 1090.35,-1265.83 1075.18,-1280.63 1087.72,-1286.86"/>
|
||||
<text text-anchor="middle" x="1137.5" y="-1335.4" font-family="Times Roman,serif" font-size="14.00">display_engine+302</text>
|
||||
<text text-anchor="middle" x="1137.5" y="-1317.4" font-family="Times Roman,serif" font-size="14.00">($47b9a)</text>
|
||||
</g>
|
||||
<!-- N_47A6C->N_48C44 -->
|
||||
<g id="edge10" class="edge"><title>N_47A6C->N_48C44</title>
|
||||
<path fill="none" stroke="red" stroke-width="2" d="M943.276,-1406.32C929.853,-1388.44 916.197,-1368.13 906,-1348 896.111,-1328.48 887.842,-1306.49 881.137,-1285.42"/>
|
||||
<polygon fill="red" stroke="red" points="887.767,-1283.16 875.302,-1266.02 874.36,-1287.19 887.767,-1283.16"/>
|
||||
<text text-anchor="middle" x="976.5" y="-1335.4" font-family="Times Roman,serif" font-size="14.00">display_engine+286</text>
|
||||
<text text-anchor="middle" x="976.5" y="-1317.4" font-family="Times Roman,serif" font-size="14.00">($47b8a)</text>
|
||||
</g>
|
||||
<!-- N_47A6C->N_4815C -->
|
||||
<g id="edge102" class="edge"><title>N_47A6C->N_4815C</title>
|
||||
<path fill="none" stroke="red" stroke-width="2" d="M909.733,-1434.21C859.833,-1414.02 796.299,-1384.41 746,-1348 715.087,-1325.62 685.311,-1296.04 660.939,-1268.92"/>
|
||||
<polygon fill="red" stroke="red" points="666.07,-1264.15 647.615,-1253.74 655.549,-1273.39 666.07,-1264.15"/>
|
||||
<text text-anchor="middle" x="816.5" y="-1335.4" font-family="Times Roman,serif" font-size="14.00">display_engine+294</text>
|
||||
<text text-anchor="middle" x="816.5" y="-1317.4" font-family="Times Roman,serif" font-size="14.00">($47b92)</text>
|
||||
</g>
|
||||
<!-- N_491EA -->
|
||||
<g id="node33" class="node"><title>N_491EA</title>
|
||||
<polygon fill="lightgray" stroke="red" points="1406,-1276 1263,-1196 1406,-1116 1549,-1196 1406,-1276"/>
|
||||
<text text-anchor="middle" x="1406" y="-1219.4" font-family="Times Roman,serif" font-size="14.00">3.04%</text>
|
||||
<text text-anchor="middle" x="1406" y="-1201.4" font-family="Times Roman,serif" font-size="14.00">4120</text>
|
||||
<text text-anchor="middle" x="1406" y="-1183.4" font-family="Times Roman,serif" font-size="14.00">initialise_freetable</text>
|
||||
<text text-anchor="middle" x="1406" y="-1165.4" font-family="Times Roman,serif" font-size="14.00">(2 calls)</text>
|
||||
</g>
|
||||
<!-- N_47A6C->N_491EA -->
|
||||
<g id="edge2" class="edge"><title>N_47A6C->N_491EA</title>
|
||||
<path fill="none" stroke="red" stroke-width="2" d="M1067.47,-1428.41C1110.83,-1406.94 1165.71,-1377.99 1212,-1348 1254.04,-1320.76 1298.2,-1286.65 1333.75,-1257.64"/>
|
||||
<polygon fill="red" stroke="red" points="1338.45,-1262.84 1349.44,-1244.72 1329.55,-1252.03 1338.45,-1262.84"/>
|
||||
<text text-anchor="middle" x="1336" y="-1335.4" font-family="Times Roman,serif" font-size="14.00">display_engine+6010</text>
|
||||
<text text-anchor="middle" x="1336" y="-1317.4" font-family="Times Roman,serif" font-size="14.00">($491e6)</text>
|
||||
</g>
|
||||
<!-- N_49B28->N_49BEA -->
|
||||
<g id="edge12" class="edge"><title>N_49B28->N_49BEA</title>
|
||||
<path fill="none" stroke="red" stroke-width="2" d="M1008.16,-802.024C1003.81,-768.947 998.834,-731.14 994.289,-696.598"/>
|
||||
<polygon fill="red" stroke="red" points="1001.22,-695.613 991.671,-676.697 987.34,-697.439 1001.22,-695.613"/>
|
||||
<text text-anchor="middle" x="1087.5" y="-745.4" font-family="Times Roman,serif" font-size="14.00">add_wall_segment+186</text>
|
||||
<text text-anchor="middle" x="1087.5" y="-727.4" font-family="Times Roman,serif" font-size="14.00">($49be2)</text>
|
||||
</g>
|
||||
<!-- N_481F8->N_48206 -->
|
||||
<g id="edge80" class="edge"><title>N_481F8->N_48206</title>
|
||||
<path fill="none" stroke="black" d="M148.23,-3061.03C210.061,-3029.26 305,-2980.48 371.423,-2946.35"/>
|
||||
<ellipse fill="black" stroke="black" cx="378.862" cy="-2942.52" rx="8.00002" ry="8.00002"/>
|
||||
<text text-anchor="middle" x="360.5" y="-3005.4" font-family="Times Roman,serif" font-size="14.00">ssector_node+12</text>
|
||||
<text text-anchor="middle" x="360.5" y="-2987.4" font-family="Times Roman,serif" font-size="14.00">($48204)</text>
|
||||
</g>
|
||||
<!-- N_481F8->N_4819C -->
|
||||
<g id="edge86" class="edge"><title>N_481F8->N_4819C</title>
|
||||
<path fill="none" stroke="black" d="M159.833,-3082.9C309.764,-3059.61 656.148,-2991.43 898,-2832 1072.94,-2716.68 1216.64,-2508.85 1282,-2404.08"/>
|
||||
<ellipse fill="black" stroke="black" cx="1286.31" cy="-2397.11" rx="8.00002" ry="8.00002"/>
|
||||
<text text-anchor="middle" x="1046" y="-2801.4" font-family="Times Roman,serif" font-size="14.00">ssector_node+2</text>
|
||||
<text text-anchor="middle" x="1046" y="-2783.4" font-family="Times Roman,serif" font-size="14.00">($481fa)</text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 61 KiB |
BIN
doc/images/devices.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
doc/images/fileselector.png
Normal file
After Width: | Height: | Size: 7.3 KiB |
BIN
doc/images/floppydisks.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
doc/images/harddisks.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
doc/images/joystick.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
doc/images/kcachegrind.png
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
doc/images/keyboard.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
doc/images/main.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
doc/images/memory.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
doc/images/monitor.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
doc/images/newfloppy.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
doc/images/screen.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
doc/images/sound.png
Normal file
After Width: | Height: | Size: 5.6 KiB |
BIN
doc/images/system.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
doc/images/tos.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
22
doc/keymap-sample.txt
Normal file
@ -0,0 +1,22 @@
|
||||
# This is an example for a keyboard mapping file that can be used in Hatari
|
||||
# by loading it from the keyboard setup dialog.
|
||||
#
|
||||
# Lines starting with a '#' or with a ';' are comments.
|
||||
# All other lines should contain exactly two numbers separated by a comma.
|
||||
#
|
||||
# The first number is the libSDL symbolic PC key code.
|
||||
# See the "--trace keymap" output from Hatari.
|
||||
#
|
||||
# The corresponding key will be mapped to the ST key which is specified by
|
||||
# second number - the ST scan code of the key. "--trace keymap" output
|
||||
# shows the already mapped scan code.
|
||||
#
|
||||
# tests/keymap/ directory contains programs to discover/test the PC SDL
|
||||
# and Atari scan code values. Hatari's default PC key code -> ST scan
|
||||
# code mappings are in src/keymap.c source file.
|
||||
#
|
||||
# Example: If you want to get the 'y' and 'z' keys right with a german TOS
|
||||
# ROM, you can use the following two lines to map the PC keys to the right
|
||||
# ST scan codes:
|
||||
121,44
|
||||
122,21
|
4309
doc/manual.html
Normal file
145
doc/memory-usage.txt
Normal file
@ -0,0 +1,145 @@
|
||||
|
||||
HATARI MEMORY USAGE
|
||||
|
||||
Here are some stats on Hatari v1.2+ memory usage (on Linux) and what
|
||||
could be done to decrease it.
|
||||
|
||||
First the binary size from "size ./hatari":
|
||||
text data bss dec
|
||||
1489120 12828 18799688 20301636
|
||||
|
||||
I.e. the Hatari binary size is 1.4MB, it has 12KB of non-const/pre-defined
|
||||
arrays and 18MB of uninitialized (at build-time) fixed size arrays.
|
||||
The names of latter are listed below.
|
||||
|
||||
To decrease the binary size slightly, disable DSP from src/Makefile,
|
||||
don't enabled tracing in config.h (latter may have trivial improvement
|
||||
on speed too). You may also try the gcc "-Os" or "-O3 -finline-limit=..."
|
||||
options, their effect depends on the architecture for which Hatari is
|
||||
being compiled.
|
||||
|
||||
|
||||
To see the objects in the Hatari 18MB BSS section, get the datadump
|
||||
script from here:
|
||||
http://live.gnome.org/MemoryReduction_2fTools
|
||||
|
||||
Compile Hatari without stripping, and use:
|
||||
datadump.py -n -s .bss -r ./hatari
|
||||
|
||||
As a result you see these array variables:
|
||||
16777216 STRam hatari
|
||||
404400 dsp_core hatari
|
||||
324048 CyclePalettes hatari
|
||||
262144 mem_banks hatari
|
||||
262144 cpufunctbl hatari
|
||||
176612 ConfigureParams hatari
|
||||
131072 pInterceptWriteTable hatari
|
||||
131072 pInterceptReadTable hatari
|
||||
69632 InternalDTAs hatari
|
||||
65536 ymout5_u16 hatari
|
||||
32768 MixBuffer hatari
|
||||
32768 DspOutBuffer hatari
|
||||
...
|
||||
|
||||
These empty arrays aren't an issue unless Hatari actually writes to
|
||||
them, but that will happen as Hatari uses them. Here are some ways
|
||||
to minimize dirtying of the related memory i.e. use of the arrays
|
||||
in Hatari:
|
||||
|
||||
* Enabling only required amount of memory for the emulation.
|
||||
Hatari doesn't dirty (zero) all of STRam, just the part of the ST ram
|
||||
that user has configured (accessible as ST ram, 0.5-14MB) and 2MB
|
||||
at the top (used as IO-memory, TOS and cartridge memory).
|
||||
|
||||
* Disabling DSP from build gets rid of dsp_core
|
||||
|
||||
* Modifying Video_ClearOnVBL() and Video_ColorReg_WriteWord()
|
||||
to call Spec512 functions only when nSpec512Threshold configuration
|
||||
value is non-zero and run Hatari with spec512 support disabled.
|
||||
This gets rid of CyclePalettes dirtying
|
||||
|
||||
* ConfigureParams size can be decreased 22*4KB by setting
|
||||
MAX_HARDDRIVES in configuration.h to one (or by removing
|
||||
memset from Configuration_SetDefault() as static variables in .bss
|
||||
are zeroed already by kernel, memset()ting them just makes them
|
||||
dirty and Configuration_SetDefault() is called only at Hatari startup).
|
||||
|
||||
|
||||
When I profiled Hatari with Valgrind (valgrind.kde.org) Massif plugin,
|
||||
it tells that Hatari does about 3MB of memory worth of dynamic
|
||||
allocations. The allocations and ways to make them smaller are:
|
||||
|
||||
* In includes/vdi.h decrease MAX_VDI_WIDTH and MAX_VDI_HEIGHT
|
||||
to 640 and 400. As Hatari allocates 2*2 framebuffers (of size
|
||||
width*height/8) for page flipping in Screen_Init(), decreasing
|
||||
their size can have have a large effect.
|
||||
|
||||
* Do not load bigfont in gui-sdl/sdlgui.c, especially if the device
|
||||
screen is smaller than VGA. Both fonts together take about 1/3 MB.
|
||||
|
||||
* Change uncompressed file read to use mmap() instead, currently
|
||||
memory is allocated for the whole disk image before reading it.
|
||||
- With normal DD floppy image Hatari would use that amount which
|
||||
might be acceptable, but with e.g. 2MB disk needed for running
|
||||
Wolf3D v0.8, mmap() sounds much better
|
||||
- For compressed disk images memory needs to be allocated for
|
||||
uncompressed image data, i.e. there we cannot save memory.
|
||||
|
||||
* Check whether the m86k instruction table could be made smaller:
|
||||
#include "uae-cpu/readcpu.h"
|
||||
printf("%d -> %d\n", sizeof(struct instr), sizeof(struct instr) * 65536);
|
||||
On x86 it's slightly over 1MB.
|
||||
|
||||
You can also Massif Hatari yourself, its allocation calltrees
|
||||
are very short & the allocations are easy to find in the Hatari
|
||||
source code.
|
||||
|
||||
|
||||
From /proc/sysvipc/shm one can see how much shared memory Hatari/libSDL
|
||||
has allocated and that it shares it with the X server:
|
||||
- >100KB in lowrez
|
||||
- ~200KB in lowrez with borders
|
||||
- ~500KB in monochrome or zoomed lowrez
|
||||
- >800KB in zoomed lowrez with borders
|
||||
|
||||
I don't think these could be made smaller from the code. Besides,
|
||||
user can just use a the smaller Hatari screen mode in fullscreen and
|
||||
let the display scale it to fullscreen.
|
||||
|
||||
|
||||
According to Xrestop, Hatari doesn't keep any Pixmap resources
|
||||
at the X server side.
|
||||
|
||||
|
||||
Finally when looking at the Hatari process with "pmap", you can
|
||||
see that the libraries Hatari links don't use so much private
|
||||
(writable) memory, only couple of hundred KB:
|
||||
pmap $(pidof hatari) | grep / | grep rw
|
||||
|
||||
To see how much from the memory pmap tells Hatari to have allocated is
|
||||
actually used/dirtied, take a peek at: /proc/$(pidof hatari)/smaps.
|
||||
|
||||
Of the rest of the 40MB Hatari VMSIZE you see in "top" (about 16MB),
|
||||
half is unused/clean 8MB memory (allocated by kernel for the SDL sound
|
||||
thread stack) and half goes to shared library code (their .text
|
||||
sections with "r-x" rights) that Hatari links against. The libraries
|
||||
are most likely used also by other programs and even if they aren't,
|
||||
it's memory mapped read-only / read in on-demand pages & pagable back
|
||||
to disk so it's shouldn't be much of a problem either.
|
||||
|
||||
|
||||
Unmodified Hatari runs on (Linux) systems having about 20MB of _free_
|
||||
memory (e.g. according to /proc/meminfo free+buffers+cached fields)
|
||||
and more RAM in total than the Hatari VMSIZE.
|
||||
|
||||
Using low-rez without borders nor zooming, setting emulated ST memory
|
||||
amount to <=1MB, limiting the VDI screen size, disabling DSP and
|
||||
removing bigfont (discussed with Massif findings above) should enable
|
||||
running Hatari well on a system with only 10MB free memory, if it's
|
||||
otherwise fast enough.
|
||||
|
||||
|
||||
- Eero Tamminen
|
||||
|
||||
PS. Any device fast enough to run Hatari at reasonable speed
|
||||
should already have enough memory for it...
|
264
doc/midi-linux.txt
Normal file
@ -0,0 +1,264 @@
|
||||
|
||||
Getting (Linux) ALSA midi support and MIDI networking working with Hatari
|
||||
=========================================================================
|
||||
|
||||
If you don't have a real MIDI sequencer, you can use the MIDI synthesizer
|
||||
of your sound card (if available) or use a software synthetizer.
|
||||
|
||||
For (Debian) package names and links to software referenced in this
|
||||
text, see end of the text. Most of the distros should have in their
|
||||
repositories packages at least for some of them though.
|
||||
|
||||
Contents:
|
||||
- Using a soundcard with built-in MIDI synthesis capability
|
||||
- Making MIDI soft-synthetizer to work with ALSA
|
||||
- Using FluidSynth instead of Timidity
|
||||
- Other software synthetizers
|
||||
- Making it all to work with Hatari
|
||||
- MIDI and networking
|
||||
- Linux & Atari MIDI related software
|
||||
- Additional documentation
|
||||
|
||||
|
||||
Using a soundcard with built-in MIDI synthesis capability
|
||||
---------------------------------------------------------
|
||||
|
||||
If your soundcard is capable of playing MIDI sound (i.e. you can play a .mid
|
||||
file with the "aplaymidi" command using the appropriate port), you can use this
|
||||
synthesis device for Hatari, too. However, you still might have to install and
|
||||
connect a virtual midi device, so that Hatari can access it through a
|
||||
/dev/snd/midiC*D* device file (see instructions below).
|
||||
|
||||
Please note that you might also have to load instrument patches into your sound
|
||||
card first, for example with the program "sfxload" for AWE64 based sound cards,
|
||||
or with the program "sbiload" for OPL3 based sound cards.
|
||||
|
||||
|
||||
Making MIDI soft-synthetizer to work with ALSA
|
||||
-----------------------------------------------
|
||||
|
||||
Make Timidity into an ALSA output device with:
|
||||
timidity -Os -iA
|
||||
(-O: output=alsa, -i: interface=alsa)
|
||||
|
||||
To make it use less CPU and be more responsive, use:
|
||||
timidity -Os -iA -B2,8 -EFreverb=0 -EFchorus=0
|
||||
(-B: 2,8=set small buffers, -EFx=0: disable effects)
|
||||
|
||||
Make vkeybd (virtual midi keyboard app) into an ALSA input device with:
|
||||
vkeybd
|
||||
Or use the newer & nicer looking "Virtual MIDI Piano Keyboard":
|
||||
vmpk
|
||||
|
||||
View the resulting (software) ALSA input and output devices:
|
||||
aconnect -i -o
|
||||
|
||||
Then connect the vkeybd output port to the timidity input port with:
|
||||
aconnect <vkeybd port> <timidity port>
|
||||
Or use one of the GUI programs for this like kaconnect, aconnectgui etc.
|
||||
|
||||
Now you can use the virtual midi keyboard for testing the sound
|
||||
synthesis.
|
||||
|
||||
|
||||
Finally you can test how well midi files are played.
|
||||
Check which ALSA port Timidity provides:
|
||||
aplaymidi -l
|
||||
|
||||
And use that port for playing a midi file:
|
||||
aplaymidi -p <port, e.g. 129:0> test.mid
|
||||
(or use 'pmidi')
|
||||
|
||||
Note: Remember that you need to re-connect the (virtual) device
|
||||
ports each time you restart them.
|
||||
|
||||
|
||||
Using FluidSynth instead of Timidity
|
||||
------------------------------------
|
||||
|
||||
Instead of Timidity, you also use other soft-synthetizers,
|
||||
like FluidSynth:
|
||||
fluidsynth --audio-driver=alsa --midi-driver=alsa_seq soundfont.sf2
|
||||
|
||||
You could play a bit with other options to get more performance,
|
||||
sound volume etc:
|
||||
--reverb=no --chorus=no -o synth.polyphony=16 --gain=0.6
|
||||
|
||||
And if you don't like the FluidSynth shell, use:
|
||||
--no-shell --server
|
||||
|
||||
Qsynth provides a GUI for above:
|
||||
qsynth <soundfont>
|
||||
|
||||
Note: FluidSynth v1.0.7a in older (obsolete) Linux distros has buffer
|
||||
overruns, but they're fixed in v1.0.8 or newer that are in the current
|
||||
Linux distros.
|
||||
|
||||
|
||||
Other software synthetizers
|
||||
---------------------------
|
||||
|
||||
Of the other soft-synthetizers, I like also Horgand organ emulator
|
||||
as it has pretty good organ sound, but it needs Jack connection kit
|
||||
(+ e.g. qjackctl) for sound to work properly (not have sound underruns).
|
||||
|
||||
|
||||
Making it all to work with Hatari
|
||||
---------------------------------
|
||||
|
||||
Hatari requires midi hardware devices to work, it doesn't support
|
||||
ALSA directly. To get the software synth ALSA devices to appear
|
||||
as HW midi devices, run following as *root*:
|
||||
modprobe snd-virmidi
|
||||
|
||||
When you list your ALSA output devices with:
|
||||
aconnect -o
|
||||
You should see in addition to the soft-synth also 4 virtual hardware
|
||||
devices.
|
||||
|
||||
Then connect (with aconnect or one of the GUIs) the first virtual
|
||||
HW port to the same soft-synth port where you connected the virtual
|
||||
midi keyboard.
|
||||
|
||||
Check which number was assigned by ALSA to the new virtual midi card:
|
||||
cat /proc/asound/cards
|
||||
|
||||
And give to Hatari the corresponding ALSA midi device. In my case
|
||||
VirMidi was Card 1 and as the port used above was first one, I give
|
||||
Hatari the following midi device:
|
||||
hatari --midi-out /dev/snd/midiC1D0
|
||||
|
||||
(For the virtual midi keyboard, give same device with --midi-in option.)
|
||||
|
||||
Note: In older (obsolete) Linux distros SDL_mixer may take exclusive
|
||||
access to the PCM (sound) device, but as the soft synthetizer is
|
||||
already connected to it, one may need to use --nosound option to get
|
||||
MIDI sound working. In recent distros this shouldn't anymore be
|
||||
a problem thanks to Pulseaudio.
|
||||
|
||||
|
||||
MIDI and networking
|
||||
-------------------
|
||||
|
||||
If you direct the MIDI data to stdout, you can use just ssh to
|
||||
forward the MIDI output over network:
|
||||
hatari --midi-in "" --midi-out /dev/stdout --log /dev/stderr |\
|
||||
ssh user@remote.site "cat>/dev/snd/midiC1D0"
|
||||
|
||||
(Note that logging is re-directed to stderr so that it doesn't
|
||||
mess the MIDI output to standard output and --midi-in is set
|
||||
empty in case you don't have MIDI input device locally.)
|
||||
|
||||
|
||||
MIDI-networking two Hatari emulators can be most easily done with socat.
|
||||
|
||||
MIDI networking over normal TCP/IP network:
|
||||
@remote.site:
|
||||
socat -b1 PTY,raw,echo=0,link=/tmp/midi1 TCP4-LISTEN:33333 &
|
||||
hatari --midi-in /tmp/midi1 --midi-out /tmp/midi1 &
|
||||
@local.site:
|
||||
socat -b1 PTY,raw,echo=0,link=/tmp/midi2 TCP4:remote.site:33333 &
|
||||
hatari --midi-in /tmp/midi2 --midi-out /tmp/midi2 &
|
||||
|
||||
Buffer size (-b) is set to one just in case (by default socat buffer
|
||||
size is 8K, but all the MIDI communication is done byte at the time).
|
||||
|
||||
You may need to open a hole into your firewall for the given port
|
||||
(here 33333). Usually there's a hole for the www-traffic in firewalls,
|
||||
but the port for that (80) is below 1000, so if you use "www" as
|
||||
the port, most likely you need to run "socat" as root. To test this
|
||||
with a single machine, use "localhost" as the "remote.site".
|
||||
|
||||
Local MIDI network:
|
||||
socat -b1 PTY,raw,echo=0,link=/tmp/midi1 PTY,raw,echo=0,link=/tmp/midi2 &
|
||||
hatari --midi-in /tmp/midi1 --midi-out /tmp/midi1 &
|
||||
hatari --midi-in /tmp/midi2 --midi-out /tmp/midi2 &
|
||||
|
||||
If you don't have "socat" installed, local-midi-ring.sh script shows how
|
||||
to join several (local) Hatari emulators into a MIDI ring using fifos.
|
||||
|
||||
|
||||
Linux & Atari MIDI related Software
|
||||
-----------------------------------
|
||||
|
||||
In Debian, the tools mentioned above come from following packages:
|
||||
- alsa-utils (aconnect, aplaymidi)
|
||||
- alsa-tools (sbiload)
|
||||
- awesfx (sfxload)
|
||||
- pmidi
|
||||
- vkeybd
|
||||
- vmpk
|
||||
- aconnectgui
|
||||
- qsynth
|
||||
- fluidsynth
|
||||
- fluid-soundfont-* (soundfonts)
|
||||
- timidity
|
||||
- horgand
|
||||
- qjackctl
|
||||
- socat
|
||||
See http://packages.debian.org/ for more details on them.
|
||||
|
||||
Below are upstream links to some of these tools.
|
||||
|
||||
Vkeybd:
|
||||
http://alsa.opensrc.org/Vkeybd
|
||||
|
||||
Virtual MIDI Piano Keyboard (vmpk):
|
||||
http://vmpk.sourceforge.net/
|
||||
|
||||
Patch (ALSA connecting) utilities:
|
||||
http://alsa.opensrc.org/AlsaMidiPatchbays
|
||||
|
||||
FluidSynth:
|
||||
http://www.iiwu.org/fluidsynth/
|
||||
|
||||
Horgand:
|
||||
http://horgand.berlios.de/
|
||||
|
||||
Soundfonts:
|
||||
http://alsa.opensrc.org/SoundFontHandling
|
||||
|
||||
List of some soft-synthetizers:
|
||||
http://alsa.opensrc.org/SoftSynths
|
||||
|
||||
Kaconnect:
|
||||
http://alsamodular.sourceforge.net/
|
||||
|
||||
QjackCtl:
|
||||
http://qjackctl.sourceforge.net/
|
||||
|
||||
socat:
|
||||
http://www.dest-unreach.org/socat/
|
||||
|
||||
|
||||
As to Atari MIDI programs, here's an incomplete list
|
||||
of games supporting MIDI music:
|
||||
http://www.atari-forum.com/viewtopic.php?f=3&t=21473&start=25#p195632
|
||||
|
||||
MidiMaze supports up to 16 players over MIDI network:
|
||||
http://en.wikipedia.org/wiki/MIDI_Maze
|
||||
|
||||
|
||||
Additional documentation
|
||||
------------------------
|
||||
|
||||
ALSA midi overview:
|
||||
http://alsa.opensrc.org/AlsaMidiOverview
|
||||
|
||||
How to set up soundcards with hardware MIDI synthesis capability (AWE & OPL3):
|
||||
https://help.ubuntu.com/community/Midi/HardwareSynthesisSetup
|
||||
|
||||
Virtual midi hardware setup:
|
||||
http://www.tldp.org/HOWTO/MIDI-HOWTO-10.html
|
||||
|
||||
Timidity Howto:
|
||||
http://lau.linuxaudio.org/TiMidity-howto.html
|
||||
|
||||
Midi with ALSA (old):
|
||||
http://www.linuxfocus.org/English/September2002/article259.shtml
|
||||
|
||||
Midi on Linux:
|
||||
http://www.linuxjournal.com/article/7773
|
||||
|
||||
MIDI, Musical Instrument Digital Interface protocol:
|
||||
http://en.wikipedia.org/wiki/Midi
|
1379
doc/release-notes.txt
Normal file
220
doc/toc.js
Normal file
@ -0,0 +1,220 @@
|
||||
/** toc.js
|
||||
|
||||
This is a simplified version of the scipt "generated_toc.js" written by:
|
||||
Stuart Langridge, July 2007
|
||||
|
||||
The script is licensed under the terms of the MIT license.
|
||||
See the following page for details:
|
||||
http://www.kryogenix.org/code/browser/generated-toc/
|
||||
|
||||
Generate a table of contents, based on headings in the page.
|
||||
|
||||
To place the TOC on the page, add
|
||||
|
||||
<div id="generated-toc"></div>
|
||||
|
||||
to the page where you want the TOC to appear. If this element
|
||||
is not present, the TOC will not appear.
|
||||
|
||||
*/
|
||||
|
||||
generated_toc = {
|
||||
generate: function() {
|
||||
// Identify our TOC element, and what it applies to
|
||||
generate_from = '2';
|
||||
tocparent = document.getElementById('generated-toc');
|
||||
if (!tocparent) {
|
||||
// They didn't specify a TOC element; exit
|
||||
return;
|
||||
}
|
||||
|
||||
// set top_node to be the element in the document under which
|
||||
// we'll be analysing headings
|
||||
top_node = document.getElementsByTagName('body')[0];
|
||||
|
||||
// If there isn't a specified header level to generate from, work
|
||||
// out what the first header level inside top_node is
|
||||
// and make that the specified header level
|
||||
if (generate_from == 0) {
|
||||
first_header_found = generated_toc.findFirstHeader(top_node);
|
||||
if (!first_header_found) {
|
||||
// there were no headers at all inside top_node!
|
||||
return;
|
||||
} else {
|
||||
generate_from = first_header_found.toLowerCase().substr(1);
|
||||
}
|
||||
}
|
||||
|
||||
// add all levels of heading we're paying attention to to the
|
||||
// headings_to_treat dictionary, ready to be filled in later
|
||||
headings_to_treat = {"h6":''};
|
||||
for (var i=5; i>= parseInt(generate_from); i--) {
|
||||
headings_to_treat["h" + i] = '';
|
||||
}
|
||||
|
||||
// get headings. We can't say
|
||||
// getElementsByTagName("h1" or "h2" or "h3"), etc, so get all
|
||||
// elements and filter them ourselves
|
||||
// need to use .all here because IE doesn't support gEBTN('*')
|
||||
nodes = top_node.all ? top_node.all : top_node.getElementsByTagName('*');
|
||||
|
||||
// put all the headings we care about in headings
|
||||
headings = [];
|
||||
for (var i=0; i<nodes.length;i++) {
|
||||
if (nodes[i].nodeName.toLowerCase() in headings_to_treat) {
|
||||
// if heading has class no-TOC, skip it
|
||||
if ((' ' + nodes[i].className + ' ').indexOf('no-TOC') != -1) {
|
||||
continue;
|
||||
}
|
||||
headings.push(nodes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// make the basic elements of the TOC itself, ready to fill into
|
||||
cur_head_lvl = "h" + generate_from;
|
||||
cur_list_el = document.createElement('ul');
|
||||
tocparent.appendChild(cur_list_el);
|
||||
|
||||
// now walk through our saved heading nodes
|
||||
for (var i=0; i<headings.length; i++) {
|
||||
this_head_el = headings[i];
|
||||
this_head_lvl = headings[i].nodeName.toLowerCase();
|
||||
if (!this_head_el.id) {
|
||||
// if heading doesn't have an ID, give it one
|
||||
//this_head_el.id = 'heading_toc_' + i;
|
||||
var id = generated_toc.innerText(this_head_el).replace(/[ \/]/g, "_");
|
||||
id = id.replace(/[^a-zA-Z0-9-_]/g, '');
|
||||
this_head_el.id = id;
|
||||
}
|
||||
|
||||
while(this_head_lvl > cur_head_lvl) {
|
||||
// this heading is at a lower level than the last one;
|
||||
// create additional nested lists to put it at the right level
|
||||
|
||||
// get the *last* LI in the current list, and add our new UL to it
|
||||
var last_listitem_el = null;
|
||||
for (var j=0; j<cur_list_el.childNodes.length; j++) {
|
||||
if (cur_list_el.childNodes[j].nodeName.toLowerCase() == 'li') {
|
||||
last_listitem_el = cur_list_el.childNodes[j];
|
||||
}
|
||||
}
|
||||
if (!last_listitem_el) {
|
||||
// there aren't any LIs, so create a new one to add the UL to
|
||||
last_listitem_el = document.createElement('li');
|
||||
}
|
||||
new_list_el = document.createElement('ul');
|
||||
last_listitem_el.appendChild(new_list_el);
|
||||
cur_list_el.appendChild(last_listitem_el);
|
||||
cur_list_el = new_list_el;
|
||||
cur_head_lvl = 'h' + (parseInt(cur_head_lvl.substr(1,1)) + 1);
|
||||
}
|
||||
|
||||
while (this_head_lvl < cur_head_lvl) {
|
||||
// this heading is at a higher level than the last one;
|
||||
// go back up the TOC to put it at the right level
|
||||
cur_list_el = cur_list_el.parentNode.parentNode;
|
||||
cur_head_lvl = 'h' + (parseInt(cur_head_lvl.substr(1,1)) - 1);
|
||||
}
|
||||
|
||||
// create a link to this heading, and add it to the TOC
|
||||
li = document.createElement('li');
|
||||
a = document.createElement('a');
|
||||
a.href = '#' + this_head_el.id;
|
||||
a.appendChild(document.createTextNode(generated_toc.innerText(this_head_el)));
|
||||
li.appendChild(a);
|
||||
cur_list_el.appendChild(li);
|
||||
}
|
||||
},
|
||||
|
||||
innerText: function(el) {
|
||||
return (typeof(el.innerText) != 'undefined') ? el.innerText :
|
||||
(typeof(el.textContent) != 'undefined') ? el.textContent :
|
||||
el.innerHTML.replace(/<[^>]+>/g, '');
|
||||
},
|
||||
|
||||
findFirstHeader: function(node) {
|
||||
// a recursive function which returns the first header it finds inside
|
||||
// node, or null if there are no functions inside node.
|
||||
var nn = node.nodeName.toLowerCase();
|
||||
if (nn.match(/^h[1-6]$/)) {
|
||||
// this node is itself a header; return our name
|
||||
return nn;
|
||||
} else {
|
||||
for (var i=0; i<node.childNodes.length; i++) {
|
||||
var subvalue = generated_toc.findFirstHeader(node.childNodes[i]);
|
||||
// if one of the subnodes finds a header, abort the loop and return it
|
||||
if (subvalue) return subvalue;
|
||||
}
|
||||
// no headers in this node at all
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
getYPos: function(el) {
|
||||
var y = 0;
|
||||
while (el && !isNaN(el.offsetTop)) {
|
||||
y += el.offsetTop;
|
||||
el = el.parentNode;
|
||||
}
|
||||
return y;
|
||||
},
|
||||
|
||||
init: function() {
|
||||
// quit if this function has already been called
|
||||
if (arguments.callee.done) return;
|
||||
|
||||
// flag this function so we don't do the same thing twice
|
||||
arguments.callee.done = true;
|
||||
|
||||
generated_toc.generate();
|
||||
|
||||
if (location.hash.length != 0) {
|
||||
// Make sure that the browser scrolled to the right location!
|
||||
var anchor = location.hash.substring(1);
|
||||
var y = generated_toc.getYPos(document.getElementById(anchor));
|
||||
if ('scrollTo' in window) {
|
||||
window.scrollTo(0, y);
|
||||
}
|
||||
else if ('scroll' in window) {
|
||||
window.scroll(0, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* Run generated_toc.init as soon as possible */
|
||||
(function(i) {
|
||||
var u =navigator.userAgent;
|
||||
var e=/*@cc_on!@*/false;
|
||||
var st = setTimeout;
|
||||
if(/webkit/i.test(u)) {
|
||||
st(function() {
|
||||
var dr=document.readyState;
|
||||
if(dr=="loaded" || dr=="complete") {
|
||||
i()
|
||||
}
|
||||
else {
|
||||
st(arguments.callee,10);
|
||||
}
|
||||
},10
|
||||
);
|
||||
}
|
||||
else if((/mozilla/i.test(u) && !/(compati)/.test(u)) || (/opera/i.test(u))) {
|
||||
document.addEventListener("DOMContentLoaded",i,false);
|
||||
} else if(e) {
|
||||
(function() {
|
||||
var t=document.createElement('doc:rdy');
|
||||
try{
|
||||
t.doScroll('left');
|
||||
i();
|
||||
t=null;
|
||||
}
|
||||
catch(e) {
|
||||
st(arguments.callee,0);
|
||||
}
|
||||
})();
|
||||
}
|
||||
else{
|
||||
window.onload=i;
|
||||
}}
|
||||
)(generated_toc.init);
|
273
doc/todo.txt
Normal file
@ -0,0 +1,273 @@
|
||||
|
||||
Hatari TO-DO list
|
||||
=================
|
||||
|
||||
If you think that you can help with one of the TO-DO list items, please get
|
||||
in touch with us.
|
||||
|
||||
|
||||
Emulation improvements
|
||||
----------------------
|
||||
|
||||
- Add fastload program header flag support to GEMDOS HD emulation
|
||||
(If PF_FASTLOAD flag is set, clear just BSS, not heap)
|
||||
|
||||
- Investigate what TOS version/functionality doesn't work for (Falcon)
|
||||
programs started from the DESKTOP/NEWDESK.INF and why, e.g:
|
||||
- Printing doesn't work with TOS versions v1.02 - v2.06
|
||||
- Colors in 2-plane VDI resolution are not set correctly
|
||||
- "Running" game preview and shareware versions crash
|
||||
- Fun's "Men at War" game or its intro don't start
|
||||
- "Push It" game crashes if auto-started
|
||||
- NoCrew: Aggressive Party II 128k combo ("Whirlpool") bombs
|
||||
- RG: "Sworm" & "Sky Fall" games want to access A: & B: when autostarted
|
||||
- JAM packer packed version of Tony Benett' "Virtual City" demo bombs
|
||||
- Sentry 2.2 packed version of Shadows' "Firestarter" demo bombs
|
||||
Note: last 3 programs can be autostarted fine with EmuTOS.
|
||||
Document that in manual (page) for the Hatari "autorun" feature.
|
||||
|
||||
- Keyboard detection sometimes fails when --fast-forward is enabled
|
||||
while TOS boots / game is loaded (e.g. Falcon Snake game packed
|
||||
with Sentry).
|
||||
|
||||
- Improve disk image formats support:
|
||||
- Add support for .STT images
|
||||
(created with the STEEM disk image program)
|
||||
- Support .DIM images created with the "Get sectors: used" option
|
||||
|
||||
- Real HD 6301 (keyboard processor of the ST) emulation.
|
||||
(Current special casing is enough for all known demos using 6301)
|
||||
|
||||
- Finish upgrading the CPU core of Hatari to the latest WinUAE
|
||||
which has better cycle accuracy needed by some programs:
|
||||
- Add Exception debugging support
|
||||
- Instead of calling Reset_Cold()/m68k_reset()/uae_reset()
|
||||
directly from newcpu.c, show user a notice (dialog)
|
||||
about what happened and let user do the reboot
|
||||
(see "Emulation reset, old-UAE vs. WinUAE core" mail-thread)
|
||||
- Make WinUAE core ST/STE emulation as good as with old UAE core
|
||||
- Document cmdline options for selecting prefetch etc
|
||||
once they're stable
|
||||
|
||||
- Get the games/demos working that are marked as non-working in the manual.
|
||||
|
||||
- Improve TT and/or Falcon emulation, especially VIDEL, e.g:
|
||||
- Palette switching during screen drawing
|
||||
- ST screen modes centering when Videl borders are enabled
|
||||
- Videl video register access (e.g. VIDEL_ScreenCounter_ReadByte()
|
||||
never changes the register value unless it had first specifically
|
||||
been written into):
|
||||
http://listengine.tuxfamily.org/lists.tuxfamily.org/hatari-devel/2013/02/msg00155.html
|
||||
|
||||
- Add SCSI hard disk emulation for Falcon/TT mode.
|
||||
|
||||
- ACSI emulation doesn't work with TOS v3 (but works for TT/EmuTOS).
|
||||
|
||||
- Add SCC serial port emulation for Falcon/TT mode.
|
||||
|
||||
- Disable VDI mode for TOS v4 as it doesn't support it (and VDI mode
|
||||
is redundant as Falcon's Videl allows similar resolutions)
|
||||
|
||||
- Fix falcon sound quality (sound is sometimes noisy).
|
||||
Sound is also toggling between nice to noise with some demos.
|
||||
|
||||
- DSP emulation / Falcon sound matrix:
|
||||
- Dsp SSI internal clock (is it used on falcon ?)
|
||||
- Verify DSP instructions cycle count, especially with external RAM
|
||||
|
||||
- FPU 80-bit precision mode (selected with FPUCW instruction, and
|
||||
extra instructions on 040), if there are programs depending on it.
|
||||
UAE core implements only support for 64-bit precision. See "m68k
|
||||
FPU precision issue" thread on debian-68k mailing list for details.
|
||||
|
||||
- The "memvalid" system variables currently have to be patched in most cases.
|
||||
For improved compatibility (e.g. the game "Yolanda") it would be better to
|
||||
skip this step, but we then run into multiple other problems, see:
|
||||
http://listengine.tuxfamily.org/lists.tuxfamily.org/hatari-devel/2011/12/msg00123.html
|
||||
|
||||
|
||||
Programs known as not fully functional (not an exhaustive list)
|
||||
---------------------------------------------------------------
|
||||
|
||||
Demos :
|
||||
- video : Omega - Full Overscan Screen, Phalanx Demo - Dragon,
|
||||
Dragonnels - Happy Island, Phaleon Demo - Future Minds,
|
||||
Decade Demo - Reset, TNT - Death Of The Left Border,
|
||||
Anomaly Demo - Menu, Delirious Demo IV - STE Detection,
|
||||
Ventura - Ultimate Dist, Syntax Terror - TCB, ICE - Kryos,
|
||||
ICE - Intruding, ICE - Jamcols, Extreme Rage, Paradox - XMas 2004,
|
||||
ICE - Space Tale, ICE - The Wave Of The Future, Snork - DNT Screen 1
|
||||
|
||||
Games :
|
||||
- ikbd : Superior 109 - Special Forces
|
||||
|
||||
|
||||
Other potential Hatari functionality improvements
|
||||
-------------------------------------------------
|
||||
|
||||
- Improved boot drive & partition handling code:
|
||||
- count partitions the same way in ACSI, IDE & GEMDOS
|
||||
- move BootDrive stuff from floppy.c e.g. to tos.c where NumDrives is
|
||||
|
||||
- Support harddisk write protection also for IDE & ACSI drives?
|
||||
|
||||
- Fix GST symbol table detection in debugger & gst2ascii. Currently
|
||||
it will just process whatever it thinks the symbol table to
|
||||
contain (which output can mess the console). MiNT binaries can
|
||||
contain GST symbol tables, so checking that isn't enough.
|
||||
|
||||
- Preliminary debugger work for the other features + cleanup:
|
||||
- Eval_Number() could take DSP/CPU flag like Eval_Range()
|
||||
does so that all commands taking numeric args can accept
|
||||
also symbol, variable & register names
|
||||
- Skip & tell user to rename any of the loaded symbols that
|
||||
have same name as internal Hatari variables
|
||||
- Change "" for expressions to {} so that quotes can
|
||||
be used for e.g. search strings?
|
||||
|
||||
- While Hatari debugger has many features that Steem one doesn't have,
|
||||
that also has debugging features missing from the Hatari debugger.
|
||||
|
||||
These ones should be straightforward to implement:
|
||||
- Breakpoints on interrupts
|
||||
- Breaking on exceptions 2-8 vs. bombs vs. don't break.
|
||||
Hatari has only an option to break on address & bus errors
|
||||
& uninitialized exception handler.
|
||||
- Showing values both in different lengths and numeric bases.
|
||||
(In Hatari one gets latter with "evaluate" command, e.g. "e a0",
|
||||
and showing the value as long/word/byte requires ANDing it)
|
||||
- All register values being shown with above info
|
||||
(= Steem Register monitor)
|
||||
- info commands for PSG, MFP, FDC and IKBD register values
|
||||
(= Steem monitors for these)
|
||||
- Info command for "timings" i.e. cycles since HBL/VBL,
|
||||
timer values, video address & scanline
|
||||
(= Steem Timings view)
|
||||
- memory dump in text format
|
||||
(= Steem Text monitor)
|
||||
- Stack content display: m "a7-$40"-"a7"
|
||||
(= Steem Stack display)
|
||||
- Text string and binary values (hex) search
|
||||
(= widgets in Steem monitor windows)
|
||||
- Run for N cycles
|
||||
(Hatari 'continue' command accepts only instructions, not cycles)
|
||||
|
||||
These are more complicated ones:
|
||||
- Monitoring reads & writes to specific address. Hatari supports
|
||||
only tracing changes to values, not having breakpoints of
|
||||
reading values or writing the same value. Slow
|
||||
- Showing breakpoints in instruction dumps. Hatari breakpoints
|
||||
are more advanced than the trivial address breakpoints, so
|
||||
this would require adding efficient support for plain PC
|
||||
based breakpoints
|
||||
- Adding new symbol names for arbitrary addresses one at the time.
|
||||
Hatari debugger currently requires new symbols to be added to
|
||||
a file containing all the symbols + reloading that file
|
||||
- Memory dump that shows also disassembly and values
|
||||
in different bases
|
||||
(= Steem Memory monitor)
|
||||
|
||||
Basic GUI debugger features:
|
||||
- Ability to open as many dump/info windows as wanted
|
||||
(hex/asm/mfp/video/sound/...) and have their content
|
||||
refreshed each time emulation is stopped.
|
||||
- A stop/run button and a debugger "step" button
|
||||
- Possibility to click to an address on dump window to define
|
||||
a simple PC breakpoint (or monitor memory on B/W/L accesses)
|
||||
- A way to search for hex/text in Hatari's RAM.
|
||||
|
||||
(See "Steem debugger features not in Hatari debugger"
|
||||
on BerliOS hatari-devel mail thread for more info.)
|
||||
|
||||
- MonST debugger features missing from Hatari debugger
|
||||
(ones not mentioned in Steem features):
|
||||
- Address breakpoints can have conditions that are evaluated
|
||||
only on that address
|
||||
- Marking breakpoint types in disassembly (<count> for counted
|
||||
ones, ? for conditional ones, * for others)
|
||||
- Shortcut command for telling to run until given
|
||||
(temporary) conditional breakpoint is hit
|
||||
- Running until code returns from ROM (exiting from super mode?)
|
||||
- Single stepping that skips Traps, Line-A, Line-F. And one that
|
||||
skips also BSRs and JSRs. Run until RTS/RTE command
|
||||
- Saving full machine status (like registers) to history buffer
|
||||
each time debugger is entered (exception or breakpoint is hit)
|
||||
and viewing of that history
|
||||
- SP & SSP as CPU register names (active & supervisor stack)
|
||||
- Fill and copy memory command
|
||||
- Search for an address which disassembly output matches
|
||||
given instruction substring
|
||||
- User variables which values can be set & used in expressions
|
||||
|
||||
- Improved screen handling:
|
||||
- Direct 16-bit & 32-bit support for monochrome and VDI modes
|
||||
(currently they're converted through 8-bit surface)
|
||||
- Line based screen change detection/checks:
|
||||
- blit only changed lines
|
||||
- simpler / faster (LED) overlay handling
|
||||
- x3 and x4 zooming routines for ST-Low resolution
|
||||
- Include some fancy zooming routines like 2xSaI or Super-Eagle
|
||||
- Add support for hardware accelerated zooming with
|
||||
SDL YUV overlays or OpenGL
|
||||
|
||||
- Check/clean RS232 code:
|
||||
- polls at 2/20ms intervals and reads data byte at the time.
|
||||
SDL_Delay()s & fgetc() could be replaced (at least on unix)
|
||||
with select() and fread(). Or just remove the rs232 thread
|
||||
and use an interrupt for it...
|
||||
- The commented out rs232 stuff could be removed from gemdos.c
|
||||
(RS emulation is done at HW, not Gemdos level).
|
||||
|
||||
- Improve directory handling:
|
||||
- Currently screenshots & anim go always to current dir,
|
||||
whereas memsave, sound recording, printer & midi & serial &
|
||||
output and log output go to file specified in config file.
|
||||
There should be support for setting also anim/screenshot
|
||||
directory / file name from config file (needs change also
|
||||
in screenSnapShot.c).
|
||||
- By default the directory config values should be empty in
|
||||
which case the code will at run-time decide to use current
|
||||
directory, but not modify the path config setting.
|
||||
|
||||
|
||||
Bug reports
|
||||
-----------
|
||||
|
||||
- Hextracker freezes at start with Falcon emulation because Videl
|
||||
screen address counter doesn't advance (its read & write are no-ops).
|
||||
|
||||
- Atari programs can crash Hatari in Falcon mode because sound DMA code isn't robust
|
||||
against bad register values:
|
||||
http://listengine.tuxfamily.org/lists.tuxfamily.org/hatari-devel/2012/02/msg00082.html
|
||||
|
||||
- When playing Tautology 2 I noticed the mod player sound goes in and out of
|
||||
sync. fading into crackle and back. (Using Hatari 1.4 with TOS 4.04 on Mac
|
||||
OS X 10.6.5)
|
||||
http://developer.berlios.de/bugs/?func=detailbug&bug_id=17781&group_id=10436
|
||||
|
||||
- Problem: On real Falcon there is a minor feature in videl. You can simply
|
||||
fade whole screen to black, if you just clear the Horizontal Border End
|
||||
($ffff8286) and start fading colors from 0 to 255 to $ffff9800 or vice versa.
|
||||
test <put picture to screen>
|
||||
move.w #255-1,d7
|
||||
moveq #0,d6
|
||||
.loop <vsync, stop#$2300>
|
||||
clr.w $ffff8286.w
|
||||
move.l d6,$ffff9800.w
|
||||
addq.l #1,d6
|
||||
dbf d7,.loop
|
||||
Now it does this exactly opposite direction, it fades bgcolor from 0 to 255.
|
||||
http://developer.berlios.de/bugs/?func=detailbug&bug_id=18002&group_id=10436
|
||||
|
||||
- To compare my real Falcon with Hatari on my Windows 7 PC, I make some short
|
||||
benchmarks with Kronos. The disk benchmark in Kronos runs in 1-2 minutes on
|
||||
my real Falcon. The same disk benchmark in Kronos under Hatari 1.5 runs
|
||||
longer than 20 minutes with GEMDOS emulation. Only when I use the AltGr + X
|
||||
option, before the benchmark runs, then the disk benchmark in kronos is
|
||||
comparable fast as my 16MHz Falcon.
|
||||
http://developer.berlios.de/bugs/?func=detailbug&bug_id=18298&group_id=10436
|
||||
|
||||
-> Hatari GEMDOS emulation needs to do a lot of extra kernel file & directory
|
||||
accesses which with current code seem unavoidable. They're a problem only
|
||||
with test programs like Kronos, for those one should consider using
|
||||
harddisk image files instead.
|
66
doc/video-recording.txt
Normal file
@ -0,0 +1,66 @@
|
||||
How to record Atari videos with Hatari
|
||||
======================================
|
||||
|
||||
Getting best output from Hatari
|
||||
-------------------------------
|
||||
|
||||
* Do NOT use external recorders (such as Quicktime X on OSX), as they
|
||||
won't get perfect framerate and sound sync like Hatari itself does.
|
||||
|
||||
* Disable (default) frame skip, either from the Hatari GUI, or with
|
||||
following command line option:
|
||||
--frameskips 0
|
||||
|
||||
* For STe you could set audio to 50066 Hz using ST table, either from
|
||||
the Hatari GUI, or with following command line options:
|
||||
--sound 50066 --ym-mixing table
|
||||
|
||||
* If you have enough free disk space, ask Hatari to use uncompressed
|
||||
AVI format for the recording with the following command line option:
|
||||
--avi-vcodec bmp
|
||||
|
||||
|
||||
Hatari AVI compression notes
|
||||
----------------------------
|
||||
|
||||
If Hatari is configured/built with PNG development installed headers
|
||||
(normal case with Linux distros and pre-built binaries), Hatari will
|
||||
use PNG compression to produce smaller AVI recordings.
|
||||
|
||||
Additionally, by default Hatari will use the highest PNG compression
|
||||
level (same as with screenshots), but this is *really* CPU intensive.
|
||||
|
||||
Because of the PNG compression CPU usage, it's better to use
|
||||
uncompressed BMP format. If you don't have enough disk space for
|
||||
this, next best option is to ask Hatari to use lower compression
|
||||
level, e.g. with:
|
||||
--png-level 4
|
||||
|
||||
Valid compression levels are 0-9, with 9 being default/highest/slowest.
|
||||
|
||||
|
||||
Preparing videos for uploading
|
||||
------------------------------
|
||||
|
||||
If the end goal is Youtube, it's recommended to run Hatari's AVI
|
||||
output through ffmpeg to do nearest neighbor upscale to 1080p. Then
|
||||
Youtube will keep the 50 FPS and you have non-fuzzy pixels in the
|
||||
recording.
|
||||
|
||||
This ffmpeg line should do the trick for a 320x200 stream (5x scale):
|
||||
ffmpeg -i hatari.avi -vf "scale=1600:1000, \
|
||||
pad=1920:1080:160:40:black" -sws_flags neighbor \
|
||||
-vcodec png -acodec copy youtube1080p.mov
|
||||
|
||||
And for a 416x276 stream (so you get the overscan area as well, 4x scale):
|
||||
ffmpeg -i hatari.avi -vf "crop=400:270:8:0, scale=1600:1080, \
|
||||
pad=1920:1080:160:0:black" -sws_flags neighbor -vcodec png \
|
||||
-acodec copy youtube1080p.mov
|
||||
|
||||
Above adds padding to 1920*1080 size, that can be removed if you trust
|
||||
the re-encoder/player to scale properly (which has been known to
|
||||
fail). It also saves the stream as PNG so it's manageable to upload
|
||||
and store for future.
|
||||
|
||||
(Upload information is based on atari-forum post by "evil":
|
||||
http://atari-forum.com/viewtopic.php?f=51&t=27595#p268185 )
|
27
etc/GP2X_Wiz/crossdefs.wiz
Normal file
@ -0,0 +1,27 @@
|
||||
#
|
||||
# CMake crossdefs for GP2X Wiz target for Hatari
|
||||
# (c) by 2011 by Matthias Arndt <marndt@asmsoftware.de>
|
||||
#
|
||||
#
|
||||
# USE AT YOUR OWN RISK and tweak as required!
|
||||
#
|
||||
# 2011-04-05 v0.01
|
||||
#
|
||||
|
||||
# this one is important
|
||||
SET(CMAKE_SYSTEM_NAME Linux)
|
||||
#this one not so much
|
||||
SET(CMAKE_SYSTEM_VERSION 1)
|
||||
|
||||
# specify the cross compiler
|
||||
SET(CMAKE_C_COMPILER /opt/arm-openwiz-linux-gnu/bin/arm-openwiz-linux-gnu-gcc)
|
||||
SET(CMAKE_CXX_COMPILER /opt/arm-openwiz-linux-gnu/bin/arm-openwiz-linux-gnu-g++)
|
||||
|
||||
# where is the target environment
|
||||
SET(CMAKE_FIND_ROOT_PATH /opt/arm-openwiz-linux-gnu/arm-openwiz-linux-gnu/sys-root-newsdl)
|
||||
|
||||
# search for programs in the build host directories
|
||||
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
# for libraries and headers in the target directories
|
||||
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
8
etc/GP2X_Wiz/hatari-wrapper.gpe
Executable file
@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# experimental Hatari launcher for GP2X Wiz
|
||||
cd hatari
|
||||
./hatari.gpe -f --bpp 16 -c ./wiz.cfg | tee ./hatari-log.txt
|
||||
sync
|
||||
cd /usr/gp2x
|
||||
exec /usr/gp2x/gp2xmenu
|
57
etc/README
Normal file
@ -0,0 +1,57 @@
|
||||
|
||||
Hatari on constrained devices
|
||||
-----------------------------
|
||||
|
||||
In this directory are Hatari configurations files for mobile etc
|
||||
devices on which the builtin Hatari defaults aren't appropriate.
|
||||
Just copy suitable config file to the device /etc/ directory as
|
||||
'hatari.cfg'.
|
||||
|
||||
Below are some comments about the configuration files. Some comments
|
||||
about suitable compiler options for these platforms can be found from
|
||||
the Hatari v1.4 default Makefile (which is now replaced with CMake):
|
||||
http://hg.tuxfamily.org/mercurialroot/hatari/hatari/file/dabb65b541c9/Makefile-default.cnf
|
||||
|
||||
Hatari v1.5 gets screen size automatically, so setting that shouldn't
|
||||
anymore be necessary, but shouldn't harm either.
|
||||
|
||||
If these configuration settings don't provide sufficient performance,
|
||||
use of an earlier Hatari version such as v0.95 (or even earlier)
|
||||
should be considered. Their emulation wasn't as accurate as in latest
|
||||
Hatari versions and therefore they're somewhat faster.
|
||||
|
||||
|
||||
n810.cfg
|
||||
--------
|
||||
|
||||
Configuration file for the Nokia 770/N800/N810 TI Omap2/ARMv6 based devices:
|
||||
- Shortcut keys adapted for the device keys:
|
||||
- Menu, Increase, Decrease, Fullscreen, Joystick keyemu fire
|
||||
- Max Hatari screen size set to device screen size
|
||||
- Options that are more suitable for the device performance:
|
||||
- Non-compatible, but faster CPU mode (works fine with most things)
|
||||
- No Falcon DSP emulation
|
||||
- High spec512 threshold
|
||||
- Automatic frameskip
|
||||
- Sensible default paths even for things that don't yet exist (to minimize
|
||||
typing when they're enabled as N770 & N800 don't have a keyboard and N810
|
||||
keyboard is very small so typing is quite awkward)
|
||||
|
||||
For more information on these devices, see e.g:
|
||||
http://en.wikipedia.org/wiki/Nokia_N800
|
||||
|
||||
|
||||
win-ce.cfg
|
||||
----------
|
||||
|
||||
Configuration file for Windows Mobile based devices:
|
||||
- Start in fullscreen mode
|
||||
- Smaller border values / screen size limited to 320x240 resolution
|
||||
- Options that are more suitable for the device performance:
|
||||
- Non-compatible (but faster) CPU mode
|
||||
- Frameskip enabled
|
||||
- High spec512 threshold
|
||||
- 11kHz sound
|
||||
|
||||
For more information on Windows CE and device based on it, see:
|
||||
http://en.wikipedia.org/wiki/Windowsce
|
200
etc/n810.cfg
Normal file
@ -0,0 +1,200 @@
|
||||
[Floppy]
|
||||
bAutoInsertDiskB = TRUE
|
||||
nWriteProtection = 2
|
||||
szDiskAFileName =
|
||||
szDiskBFileName =
|
||||
szDiskImageDirectory = /home/user/MyDocs/.games
|
||||
szDiskAZipPath =
|
||||
szDiskBZipPath =
|
||||
|
||||
[HardDisk]
|
||||
bBootFromHardDisk = TRUE
|
||||
bUseHardDiskDirectory = TRUE
|
||||
bUseHardDiskImage = FALSE
|
||||
szHardDiskDirectory = /home/user/MyDocs
|
||||
szHardDiskImage = /home/user/MyDocs/acsi.img
|
||||
bUseIdeMasterHardDiskImage = FALSE
|
||||
bUseIdeSlaveHardDiskImage = FALSE
|
||||
szIdeMasterHardDiskImage = /home/user/MyDocs/ide-master.img
|
||||
szIdeSlaveHardDiskImage = /home/user/MyDocs/ide-slave.img
|
||||
|
||||
[Joystick0]
|
||||
bEnableAutoFire = FALSE
|
||||
nJoyId = 1
|
||||
nJoystickMode = 0
|
||||
# 5-way rocker keys (arrows + enter)
|
||||
nKeyCodeDown = 274
|
||||
nKeyCodeFire = 13
|
||||
nKeyCodeLeft = 276
|
||||
nKeyCodeRight = 275
|
||||
nKeyCodeUp = 273
|
||||
|
||||
[Joystick1]
|
||||
bEnableAutoFire = FALSE
|
||||
nJoyId = 0
|
||||
nJoystickMode = 0
|
||||
nKeyCodeDown = 274
|
||||
nKeyCodeFire = 13
|
||||
nKeyCodeLeft = 276
|
||||
nKeyCodeRight = 275
|
||||
nKeyCodeUp = 273
|
||||
|
||||
[Joystick2]
|
||||
bEnableAutoFire = FALSE
|
||||
nJoyId = 2
|
||||
nJoystickMode = 0
|
||||
nKeyCodeDown = 274
|
||||
nKeyCodeFire = 13
|
||||
nKeyCodeLeft = 276
|
||||
nKeyCodeRight = 275
|
||||
nKeyCodeUp = 273
|
||||
|
||||
[Joystick3]
|
||||
bEnableAutoFire = FALSE
|
||||
nJoyId = 3
|
||||
nJoystickMode = 0
|
||||
nKeyCodeDown = 274
|
||||
nKeyCodeFire = 13
|
||||
nKeyCodeLeft = 276
|
||||
nKeyCodeRight = 275
|
||||
nKeyCodeUp = 273
|
||||
|
||||
[Joystick4]
|
||||
bEnableAutoFire = FALSE
|
||||
nJoyId = 4
|
||||
nJoystickMode = 0
|
||||
nKeyCodeDown = 274
|
||||
nKeyCodeFire = 13
|
||||
nKeyCodeLeft = 276
|
||||
nKeyCodeRight = 275
|
||||
nKeyCodeUp = 273
|
||||
|
||||
[Joystick5]
|
||||
bEnableAutoFire = FALSE
|
||||
nJoyId = 5
|
||||
nJoystickMode = 0
|
||||
nKeyCodeDown = 274
|
||||
nKeyCodeFire = 13
|
||||
nKeyCodeLeft = 276
|
||||
nKeyCodeRight = 275
|
||||
nKeyCodeUp = 273
|
||||
|
||||
[Memory]
|
||||
bAutoSave = FALSE
|
||||
nMemorySize = 1
|
||||
szAutoSaveFileName = /home/user/.hatari/auto.sav
|
||||
szMemoryCaptureFileName = /home/user/MyDocs/.games/hatari.sav
|
||||
|
||||
[Midi]
|
||||
bEnableMidi = FALSE
|
||||
sMidiInFileName = /dev/snd/midiC1D0
|
||||
sMidiOutFileName = /dev/snd/midiC1D0
|
||||
|
||||
[Printer]
|
||||
bEnablePrinting = FALSE
|
||||
bPrintToFile = TRUE
|
||||
szPrintToFileName = /home/user/MyDocs/.documents/hatari-printer.txt
|
||||
|
||||
[ROM]
|
||||
szCartridgeImageFileName =
|
||||
szTosImageFileName = /usr/share/hatari/tos.img
|
||||
|
||||
[RS232]
|
||||
bEnableRS232 = FALSE
|
||||
szOutFileName = /dev/modem
|
||||
szInFileName = /dev/modem
|
||||
|
||||
[Screen]
|
||||
bAllowOverscan = FALSE
|
||||
bFullScreen = FALSE
|
||||
bUseExtVdiResolutions = FALSE
|
||||
nForceBpp = 0
|
||||
nSpec512Threshold = 128
|
||||
nFrameSkips = 5
|
||||
nMonitorType = 1
|
||||
nVdiColors = 0
|
||||
nVdiWidth = 800
|
||||
nVdiHeight = 480
|
||||
bShowStatusbar = TRUE
|
||||
bShowDriveLed = FALSE
|
||||
bAspectCorrect = TRUE
|
||||
nMaxWidth = 800
|
||||
nMaxHeight = 480
|
||||
|
||||
[ShortcutsWithModifiers]
|
||||
# check /usr/include/SDL/SDL_keysyms.h for numeric key values
|
||||
keyOptions = 111
|
||||
keyFullScreen = 102
|
||||
keyMouseMode = 109
|
||||
keyColdReset = 99
|
||||
keyWarmReset = 114
|
||||
keyScreenShot = 103
|
||||
keyBossKey = 105
|
||||
keyCursorEmu = 106
|
||||
keyRecAnim = 97
|
||||
keyRecSound = 121
|
||||
keySound = 115
|
||||
keyQuit = 113
|
||||
keyFastForward = 120
|
||||
keyPause = 0
|
||||
keyDebugger = 19
|
||||
keyLoadMem = 108
|
||||
keySaveMem = 107
|
||||
keyInsertDiskA = 100
|
||||
|
||||
[ShortcutsWithoutModifiers]
|
||||
# 285: F4 (menu)
|
||||
keyOptions = 285
|
||||
# 287: F6 (fullsceen)
|
||||
keyFullScreen = 287
|
||||
keyMouseMode = 0
|
||||
keyColdReset = 0
|
||||
keyWarmReset = 0
|
||||
keyScreenShot = 0
|
||||
keyBossKey = 0
|
||||
# 289: F8 (+ increase)
|
||||
keyCursorEmu = 289
|
||||
keyRecAnim = 0
|
||||
keyRecSound = 0
|
||||
# 288: F7 (- decrease)
|
||||
keySound = 288
|
||||
keyQuit = 0
|
||||
keyFastForward = 0
|
||||
keyPause = 19
|
||||
keyDebugger = 0
|
||||
keyLoadMem = 0
|
||||
keySaveMem = 0
|
||||
keyInsertDiskA = 0
|
||||
|
||||
[Sound]
|
||||
bEnableSound = TRUE
|
||||
szYMCaptureFileName = /home/user/MyDocs/.sounds/hatari.wav
|
||||
nPlaybackFreq = 44100
|
||||
|
||||
[System]
|
||||
bBlitter = FALSE
|
||||
bCompatibleCpu = FALSE
|
||||
bFastForward = FALSE
|
||||
bPatchTimerD = TRUE
|
||||
bRealTimeClock = TRUE
|
||||
nCpuFreq = 8
|
||||
nCpuLevel = 0
|
||||
nDSPType = 0
|
||||
nMachineType = 0
|
||||
|
||||
[Log]
|
||||
sLogFileName = stderr
|
||||
sTraceFileName = stderr
|
||||
nTextLogLevel = 4
|
||||
nAlertDlgLogLevel = 1
|
||||
bConfirmQuit = TRUE
|
||||
|
||||
[Debugger]
|
||||
nNumberBase = 10
|
||||
nDisasmLines = 8
|
||||
nMemdumpLines = 8
|
||||
|
||||
[Keyboard]
|
||||
bDisableKeyRepeat = FALSE
|
||||
nKeymapType = 0
|
||||
szMappingFileName =
|
52
etc/win-ce.cfg
Normal file
@ -0,0 +1,52 @@
|
||||
[Log]
|
||||
sLogFileName = hatarilog.txt
|
||||
nTextLogLevel = 3
|
||||
nAlertDlgLogLevel = 3
|
||||
bConfirmQuit = TRUE
|
||||
|
||||
[Screen]
|
||||
bFullScreen = TRUE
|
||||
bAllowOverscan = FALSE
|
||||
nForceBpp = 0
|
||||
nSpec512Threshold = 128
|
||||
bUseExtVdiResolutions = FALSE
|
||||
nVdiWidth = 320
|
||||
nVdiHeight = 240
|
||||
nVdiColors = 2
|
||||
nMonitorType = 1
|
||||
nFrameSkips = 5
|
||||
bAspectCorrect = TRUE
|
||||
bShowStatusbar = FALSE
|
||||
bShowDriveLed = FALSE
|
||||
nMaxWidth = 320
|
||||
nMaxHeight = 240
|
||||
|
||||
[Joystick1]
|
||||
nJoystickMode = 2
|
||||
bEnableAutoFire = FALSE
|
||||
nJoyId = 0
|
||||
nKeyCodeUp = 273
|
||||
nKeyCodeDown = 274
|
||||
nKeyCodeLeft = 276
|
||||
nKeyCodeRight = 275
|
||||
nKeyCodeFire = 305
|
||||
bEnableJumpOnFire2 = FALSE
|
||||
|
||||
[Keyboard]
|
||||
bDisableKeyRepeat = TRUE
|
||||
nKeymapType = 0
|
||||
szMappingFileName =
|
||||
|
||||
[ShortcutsWithoutModifiers]
|
||||
keyOptions = 282
|
||||
|
||||
[Sound]
|
||||
bEnableSound = TRUE
|
||||
nPlaybackFreq = 22050
|
||||
|
||||
[Memory]
|
||||
nMemorySize = 1
|
||||
bAutoSave = FALSE
|
||||
|
||||
[System]
|
||||
bCompatibleCpu = FALSE
|
200
etc/wiz.cfg
Executable file
@ -0,0 +1,200 @@
|
||||
[Floppy]
|
||||
bAutoInsertDiskB = TRUE
|
||||
nWriteProtection = 2
|
||||
szDiskAFileName = /mnt/sd/game/hatari/FANTASIA.st
|
||||
szDiskBFileName =
|
||||
szDiskImageDirectory = /mnt/sd/game/hatari/
|
||||
szDiskAZipPath =
|
||||
szDiskBZipPath =
|
||||
|
||||
[HardDisk]
|
||||
bBootFromHardDisk = FALSE
|
||||
bUseHardDiskDirectory = FALSE
|
||||
bUseHardDiskImage = FALSE
|
||||
szHardDiskDirectory =
|
||||
szHardDiskImage =
|
||||
bUseIdeMasterHardDiskImage = FALSE
|
||||
bUseIdeSlaveHardDiskImage = FALSE
|
||||
szIdeMasterHardDiskImage =
|
||||
szIdeSlaveHardDiskImage =
|
||||
|
||||
[Joystick0]
|
||||
bEnableAutoFire = FALSE
|
||||
nJoyId = 0
|
||||
nJoystickMode = 0
|
||||
# 5-way rocker keys (arrows + enter)
|
||||
nKeyCodeDown = 274
|
||||
nKeyCodeFire = 13
|
||||
nKeyCodeLeft = 276
|
||||
nKeyCodeRight = 275
|
||||
nKeyCodeUp = 273
|
||||
|
||||
[Joystick1]
|
||||
bEnableAutoFire = FALSE
|
||||
nJoyId = 1
|
||||
nJoystickMode = 0
|
||||
nKeyCodeDown = 274
|
||||
nKeyCodeFire = 13
|
||||
nKeyCodeLeft = 276
|
||||
nKeyCodeRight = 275
|
||||
nKeyCodeUp = 273
|
||||
|
||||
[Joystick2]
|
||||
bEnableAutoFire = FALSE
|
||||
nJoyId = 2
|
||||
nJoystickMode = 0
|
||||
nKeyCodeDown = 274
|
||||
nKeyCodeFire = 13
|
||||
nKeyCodeLeft = 276
|
||||
nKeyCodeRight = 275
|
||||
nKeyCodeUp = 273
|
||||
|
||||
[Joystick3]
|
||||
bEnableAutoFire = FALSE
|
||||
nJoyId = 3
|
||||
nJoystickMode = 0
|
||||
nKeyCodeDown = 274
|
||||
nKeyCodeFire = 13
|
||||
nKeyCodeLeft = 276
|
||||
nKeyCodeRight = 275
|
||||
nKeyCodeUp = 273
|
||||
|
||||
[Joystick4]
|
||||
bEnableAutoFire = FALSE
|
||||
nJoyId = 4
|
||||
nJoystickMode = 0
|
||||
nKeyCodeDown = 274
|
||||
nKeyCodeFire = 13
|
||||
nKeyCodeLeft = 276
|
||||
nKeyCodeRight = 275
|
||||
nKeyCodeUp = 273
|
||||
|
||||
[Joystick5]
|
||||
bEnableAutoFire = FALSE
|
||||
nJoyId = 5
|
||||
nJoystickMode = 0
|
||||
nKeyCodeDown = 274
|
||||
nKeyCodeFire = 13
|
||||
nKeyCodeLeft = 276
|
||||
nKeyCodeRight = 275
|
||||
nKeyCodeUp = 273
|
||||
|
||||
[Memory]
|
||||
bAutoSave = FALSE
|
||||
nMemorySize = 1
|
||||
szAutoSaveFileName = /mnt/sd/game/hatari/auto.sav
|
||||
szMemoryCaptureFileName = /mnt/sd/game/hatari/hatari.sav
|
||||
|
||||
[Midi]
|
||||
bEnableMidi = FALSE
|
||||
sMidiInFileName = /dev/snd/midiC1D0
|
||||
sMidiOutFileName = /dev/snd/midiC1D0
|
||||
|
||||
[Printer]
|
||||
bEnablePrinting = FALSE
|
||||
bPrintToFile = TRUE
|
||||
szPrintToFileName = /mnt/sd/game/hatari/hatari-printer.txt
|
||||
|
||||
[ROM]
|
||||
szCartridgeImageFileName =
|
||||
szTosImageFileName = /mnt/sd/game/hatari/tos.img
|
||||
|
||||
[RS232]
|
||||
bEnableRS232 = FALSE
|
||||
szOutFileName = /dev/modem
|
||||
szInFileName = /dev/modem
|
||||
|
||||
[Screen]
|
||||
bAllowOverscan = FALSE
|
||||
bFullScreen = TRUE
|
||||
bUseExtVdiResolutions = FALSE
|
||||
nForceBpp = 16
|
||||
nSpec512Threshold = 128
|
||||
nFrameSkips = 2
|
||||
nMonitorType = 1
|
||||
nVdiColors = 0
|
||||
nVdiWidth = 320
|
||||
nVdiHeight = 240
|
||||
bShowStatusbar = FALSE
|
||||
bShowDriveLed = FALSE
|
||||
bAspectCorrect = FALSE
|
||||
nMaxWidth = 320
|
||||
nMaxHeight = 240
|
||||
|
||||
[ShortcutsWithModifiers]
|
||||
# check /usr/include/SDL/SDL_keysyms.h for numeric key values
|
||||
keyOptions = 111
|
||||
keyFullScreen = 102
|
||||
keyMouseMode = 109
|
||||
keyColdReset = 99
|
||||
keyWarmReset = 114
|
||||
keyScreenShot = 103
|
||||
keyBossKey = 105
|
||||
keyCursorEmu = 106
|
||||
keyRecAnim = 97
|
||||
keyRecSound = 121
|
||||
keySound = 115
|
||||
keyQuit = 113
|
||||
keyFastForward = 120
|
||||
keyPause = 0
|
||||
keyDebugger = 19
|
||||
keyLoadMem = 108
|
||||
keySaveMem = 107
|
||||
keyInsertDiskA = 100
|
||||
|
||||
[ShortcutsWithoutModifiers]
|
||||
# 285: F4 (menu)
|
||||
keyOptions = 285
|
||||
# 287: F6 (fullsceen)
|
||||
keyFullScreen = 287
|
||||
keyMouseMode = 0
|
||||
keyColdReset = 0
|
||||
keyWarmReset = 0
|
||||
keyScreenShot = 0
|
||||
keyBossKey = 0
|
||||
# 289: F8 (+ increase)
|
||||
keyCursorEmu = 289
|
||||
keyRecAnim = 0
|
||||
keyRecSound = 0
|
||||
# 288: F7 (- decrease)
|
||||
keySound = 288
|
||||
keyQuit = 0
|
||||
keyFastForward = 0
|
||||
keyPause = 19
|
||||
keyDebugger = 0
|
||||
keyLoadMem = 0
|
||||
keySaveMem = 0
|
||||
keyInsertDiskA = 0
|
||||
|
||||
[Sound]
|
||||
bEnableSound = TRUE
|
||||
szYMCaptureFileName = /mnt/sd/game/hatari/hatari.wav
|
||||
nPlaybackFreq = 22050
|
||||
|
||||
[System]
|
||||
bBlitter = FALSE
|
||||
bCompatibleCpu = FALSE
|
||||
bFastForward = FALSE
|
||||
bPatchTimerD = TRUE
|
||||
bRealTimeClock = FALSE
|
||||
nCpuFreq = 8
|
||||
nCpuLevel = 0
|
||||
nDSPType = 0
|
||||
nMachineType = 0
|
||||
|
||||
[Log]
|
||||
sLogFileName = stderr
|
||||
sTraceFileName = stderr
|
||||
nTextLogLevel = 4
|
||||
nAlertDlgLogLevel = 1
|
||||
bConfirmQuit = FALSE
|
||||
|
||||
[Debugger]
|
||||
nNumberBase = 10
|
||||
nDisasmLines = 8
|
||||
nMemdumpLines = 8
|
||||
|
||||
[Keyboard]
|
||||
bDisableKeyRepeat = FALSE
|
||||
nKeymapType = 0
|
||||
szMappingFileName =
|
339
gpl.txt
Normal file
@ -0,0 +1,339 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
108
hatari.spec
Normal file
@ -0,0 +1,108 @@
|
||||
#
|
||||
# RPM spec file for Hatari
|
||||
#
|
||||
# This file and all modifications and additions to the pristine
|
||||
# package are under the same license as the package itself.
|
||||
#
|
||||
|
||||
BuildRequires: bash coreutils cpio cpp diffutils file filesystem findutils glibc glibc-devel grep groff gzip libgcc m4 make man mktemp patch readline sed tar unzip util-linux zlib zlib-devel SDL SDL-devel autoconf binutils gcc libtool rpm
|
||||
|
||||
Name: hatari
|
||||
URL: http://hatari.tuxfamily.org/
|
||||
License: GPL
|
||||
Group: System/Emulators/Other
|
||||
Autoreqprov: on
|
||||
Version: 1.9.0
|
||||
Release: 1
|
||||
Summary: an Atari ST emulator suitable for playing games
|
||||
Source: %{name}-%{version}.tar.gz
|
||||
#Patch: %{name}-%{version}.dif
|
||||
BuildRoot: %{_tmppath}/%{name}-%{version}-build
|
||||
Prefix: /usr
|
||||
|
||||
%description
|
||||
Hatari is an emulator for the Atari ST, STE, TT and Falcon computers.
|
||||
The Atari ST was a 16/32 bit computer system which was first released by Atari
|
||||
in 1985. Using the Motorola 68000 CPU, it was a very popular computer having
|
||||
quite a lot of CPU power at that time.
|
||||
Unlike many other Atari ST emulators which try to give you a good environment
|
||||
for running GEM applications, Hatari tries to emulate the hardware of a ST as
|
||||
close as possible so that it is able to run most of the old ST games and demos.
|
||||
|
||||
%prep
|
||||
%setup
|
||||
#%patch
|
||||
|
||||
%build
|
||||
# LDFLAGS="-static" LIBS=`sdl-config --static-libs` \
|
||||
CFLAGS="-O3 -fomit-frame-pointer" \
|
||||
./configure --prefix=/usr --sysconfdir=/etc
|
||||
make
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
make install DESTDIR=$RPM_BUILD_ROOT
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%files
|
||||
%defattr(-,root,root)
|
||||
/usr/bin/hatari
|
||||
/usr/share/hatari
|
||||
%doc %_mandir/man1/hatari.1*
|
||||
%dir %_docdir/%{name}
|
||||
%_docdir/%{name}/*.txt
|
||||
%_docdir/%{name}/*.html
|
||||
%dir %_docdir/%{name}/images
|
||||
%_docdir/%{name}/images/*.png
|
||||
|
||||
%changelog -n hatari
|
||||
|
||||
* Thu Sep 10 2015 - Nicolas Pomarede
|
||||
- Hatari version 1.9.0
|
||||
|
||||
* Wed Jul 30 2014 - Nicolas Pomarede
|
||||
- Hatari version 1.8.0
|
||||
|
||||
* Sun Jun 24 2013 - Nicolas Pomarede
|
||||
- Hatari version 1.7.0
|
||||
|
||||
* Sun Jun 24 2012 - Nicolas Pomarede
|
||||
- Hatari version 1.6.2
|
||||
|
||||
* Fri Jan 13 2012 - Nicolas Pomarede
|
||||
- Hatari version 1.6.1
|
||||
|
||||
* Sun Jan 1st 2012 - Nicolas Pomarede
|
||||
- Hatari "Happy New Year 2012" version 1.6.0
|
||||
|
||||
* Tue Jul 19 2011 - Nicolas Pomarede
|
||||
- Hatari version 1.5.0
|
||||
|
||||
* Sat Jun 12 2010 - Nicolas Pomarede
|
||||
- Hatari version 1.4.0
|
||||
|
||||
* Sat Sep 05 2009 - Thomas Huth
|
||||
- Hatari version 1.3.1
|
||||
|
||||
* Sun Aug 16 2009 - Thomas Huth
|
||||
- Hatari version 1.3.0
|
||||
|
||||
* Sat Jan 24 2009 - Thomas Huth
|
||||
- Hatari version 1.2.0
|
||||
|
||||
* Sat Nov 29 2008 - Thomas Huth
|
||||
- Hatari version 1.1.0
|
||||
|
||||
* Wed Jan 02 2008 - Thomas Huth
|
||||
- Adapted RPM to the latest source code level (aiming at version 1.0.0)
|
||||
|
||||
* Sun May 06 2007 - Thomas Huth
|
||||
- Adapted spec file to be able to build Hatari with RedHat, too
|
||||
|
||||
* Sun Aug 27 2006 - Thomas Huth
|
||||
- Upgraded to version 0.90
|
||||
|
||||
* Tue Oct 18 2005 - Thomas Huth
|
||||
- initial package
|
7
python-ui/.cvsignore
Normal file
@ -0,0 +1,7 @@
|
||||
config.pyc
|
||||
debugui.pyc
|
||||
dialogs.pyc
|
||||
hatari-console.pyc
|
||||
hatari.pyc
|
||||
hatariui.pyc
|
||||
uihelpers.pyc
|
28
python-ui/CMakeLists.txt
Normal file
@ -0,0 +1,28 @@
|
||||
# conftypes.py is created to source directory (instead of build directory)
|
||||
# so that Hatari UI can be tested directly from the source directory
|
||||
add_custom_command(OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/conftypes.py
|
||||
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/gentypes.py < ${CMAKE_CURRENT_SOURCE_DIR}/../src/configuration.c > ${CMAKE_CURRENT_SOURCE_DIR}/conftypes.py
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../src/configuration.c ${CMAKE_CURRENT_SOURCE_DIR}/gentypes.py)
|
||||
add_custom_target(conftypes ALL DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/conftypes.py)
|
||||
|
||||
INSTALL(PROGRAMS hatariui
|
||||
DESTINATION ${BINDIR})
|
||||
|
||||
INSTALL(PROGRAMS hatariui.py debugui.py
|
||||
DESTINATION ${DATADIR}/hatariui/)
|
||||
|
||||
INSTALL(FILES README TODO release-notes.txt hatari-icon.png hatari-logo.png
|
||||
config.py dialogs.py hatari.py uihelpers.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/conftypes.py
|
||||
DESTINATION ${DATADIR}/hatariui/)
|
||||
|
||||
INSTALL(FILES hatariui.desktop
|
||||
DESTINATION share/applications)
|
||||
|
||||
# if(UNIX)
|
||||
add_custom_target(hatariui_man ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/hatariui.1.gz)
|
||||
add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/hatariui.1.gz
|
||||
COMMAND gzip -c -9 ${CMAKE_CURRENT_SOURCE_DIR}/hatariui.1 > ${CMAKE_CURRENT_BINARY_DIR}/hatariui.1.gz
|
||||
DEPENDS hatariui.1)
|
||||
INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/hatariui.1.gz DESTINATION ${MANDIR})
|
||||
# endif(UNIX)
|
20
python-ui/FILES
Normal file
@ -0,0 +1,20 @@
|
||||
Code:
|
||||
- config.py - Hatari configuration INI file handling
|
||||
- debugui.py - Debugger UI (works also as standalone)
|
||||
- dialogs.py - Different dialogs shown by Hatari UI
|
||||
- hatari.py - Communication with Hatari and config option handling
|
||||
- hatariui - Wrapper script for hatariui.py with suitable default options
|
||||
- hatariui.py - Hatari UI main: option handling, main window etc
|
||||
- Makefile - Rules for installing
|
||||
- uihelpers.py - Misc helpers for Hatari UI
|
||||
|
||||
Data files:
|
||||
- hatari-icon.png - Window icon
|
||||
- hatari.png - About dialog image
|
||||
- hatariui.desktop - Hatari UI .desktop file for application launchers
|
||||
|
||||
Documentation:
|
||||
- release-notes.txt - UI & code changes
|
||||
- FILES - This file
|
||||
- README - Hatari UI intro / description
|
||||
- TODO - missing features etc
|
78
python-ui/README
Normal file
@ -0,0 +1,78 @@
|
||||
Hatari UI
|
||||
---------
|
||||
|
||||
Hatari UI is an out-of-process user interface for the Hatari Atari
|
||||
ST/STe/TT/Falcon emulator and its built-in debugger which can
|
||||
(optionally) embed the Hatari emulator window.
|
||||
|
||||
Having the UI in another process allows doing it with a higher level
|
||||
language while avoiding adding GUI toolkit dependencies to Hatari
|
||||
itself. The UI is done with PyGtk i.e. in Python language, using the
|
||||
Gtk widget set.
|
||||
|
||||
The main points of this new UI over the Hatari internal one are its
|
||||
configurability, more usable file selector, internationalization
|
||||
support and providing a GUI for the (console based) debugger included
|
||||
with the Hatari emulator.
|
||||
|
||||
Note: this is an additional UI, the built-in Hatari SDL UI isn't being
|
||||
replaced or going anywhere!
|
||||
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
My guess at the required versions for the dependencies are:
|
||||
- Python >= 2.6
|
||||
- PyGtk >= 2.12 (on Debian/Ubuntu PyGtk is in python-gtk2 package)
|
||||
|
||||
Hatari UI is included with the Hatari sources:
|
||||
http://hg.tuxfamily.org/mercurialroot/hatari/hatari/file/tip/python-ui
|
||||
|
||||
Hatari UI has been tested on several Linux versions. I would assume
|
||||
it to work also on other unix systems such as Apple OSX. It may work
|
||||
with the Hatari Windows version, as long as it is built with socket
|
||||
support.
|
||||
|
||||
Embedding the Hatari emulator window is currently supported only for
|
||||
systems using an X window system (from libSDL sources it would seem
|
||||
that Windows would also support window embedding, but support for that
|
||||
would need to be added both to Hatari and Hatari UI because SDL's
|
||||
own embedding disables all keyboard events in SDL program).
|
||||
|
||||
Here are instructions on installing the dependencies for non-Linux
|
||||
platforms (neither tested nor supported as I don't use/have them):
|
||||
http://pygtk.org/downloads.html
|
||||
|
||||
|
||||
Running
|
||||
-------
|
||||
|
||||
Being a Python program, Hatari UI doesn't need to be built.
|
||||
You can just run it from where you extracted it (or checked
|
||||
it out of TuxFamily HG repo) by calling its wrapper script:
|
||||
/path/to/script/hatariui
|
||||
|
||||
Or you can run just the debugger:
|
||||
/path/to/script/debugui.py
|
||||
|
||||
But you can also install it to system along with Hatari:
|
||||
make install
|
||||
|
||||
|
||||
Notes
|
||||
-----
|
||||
|
||||
Hatari UI runs a Hatari version found on $PATH. If you want
|
||||
to use a version of Hatari that hasn't been installed, you
|
||||
need to modify the search path, for example like this:
|
||||
PATH=../build/src:.:$PATH hatariui
|
||||
|
||||
If UI is started without the embedding option, the actions
|
||||
(in menus and toolbars) have also shortcuts. They cannot
|
||||
be used when Hatari window is embedded because then those
|
||||
shortcuts couldn't be used with Hatari.
|
||||
|
||||
|
||||
A www-page with more information about Hatari UI is here:
|
||||
http://koti.mbnet.fi/tammat/hatari/hatari-ui.shtml
|
61
python-ui/TODO
Normal file
@ -0,0 +1,61 @@
|
||||
TODO
|
||||
====
|
||||
|
||||
This lists potential TODO items that aren't listed in the Hatari/UI
|
||||
sources.
|
||||
|
||||
* Separate "Atari monitor" and "Hatari window" settings dialogs
|
||||
(move options from "Display" and monitor setting from "Machine"
|
||||
dialogs to here and add VDI options to Atari Monitor dialog)
|
||||
|
||||
* Features for Help menu:
|
||||
- Create empty floppy images (+ convert directories to hard disks?)
|
||||
- MSA<->ST converter
|
||||
- ZIP->ST converter
|
||||
|
||||
* Add more Hatari debugger features to the debug UI:
|
||||
- DSP support
|
||||
- History support
|
||||
- Profiling support
|
||||
- DSP symbols loading
|
||||
(CPU symbols are loaded automatically from programs)
|
||||
- Support for stepping the emulation (both step & next commands)
|
||||
- multiple views to memory (refreshed whenever emulation is stopped)
|
||||
- supporting also register relative views (register values
|
||||
parsing should move to common functionality first)
|
||||
- breakpoint support (issue: how to stop emulation on breakpoint
|
||||
but still allow Hatari to process remote commands?)
|
||||
- trace & debug log viewers?
|
||||
|
||||
* Put all configuration stuff into single notebook dialog?
|
||||
|
||||
* Translation support for the UI:
|
||||
- use gettext
|
||||
- build needs to build & install message catalogs
|
||||
- some way for Hatari to forward dialog ID to the remote UI
|
||||
with dialog string parameters (filenames etc) which then
|
||||
need to be localized too & shown...
|
||||
|
||||
* Hatari UI specific configuration which stores:
|
||||
- list of last used configuration files which would be shown
|
||||
either in their own menu or dialog
|
||||
- list of last used memory snapshots (10?)
|
||||
- disk image dir (uses Hatari config value as default)
|
||||
- trace settings
|
||||
- remove dialog specific load/save stuff
|
||||
- screenshot name
|
||||
- needs support also to Hatari src/screenSnapShot.c
|
||||
|
||||
* Supporting other, less important Hatari configuration options:
|
||||
- HD booting, toggling disk-b autoinsertion
|
||||
- something for multiple GEMDOS partition directories
|
||||
- separate A/B disk paths for images that are within ZIP archives
|
||||
- joystick autofire toggling, defining the keys for joyemu
|
||||
- keyboard repeat, key mapping type and file, mouse grabbing
|
||||
- vdi planes and size, SDL bpp forcing, spec512 threshold, ST blitter
|
||||
- cartridge image (where? it has many limitations)
|
||||
- log file and levels, console output, bios intercept, run-VBLs
|
||||
(Many of these aren't supported by the internal Hatari UI either, or
|
||||
are missing corresponding command line options so they will require
|
||||
additional support on the Hatari control.c side too or they can
|
||||
be only enabled at boot, not disabled.)
|
270
python-ui/config.py
Normal file
@ -0,0 +1,270 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Class and helper functions for handling (Hatari) INI style
|
||||
# configuration files: loading, saving, setting/getting variables,
|
||||
# mapping them to sections, listing changes
|
||||
#
|
||||
# Copyright (C) 2008-2012 by Eero Tamminen
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
import os
|
||||
# mapping from Hatari config variable name to type id (Bool, Int, String)
|
||||
from conftypes import conftypes
|
||||
|
||||
# ------------------------------------------------------
|
||||
# Helper functions for type safe Hatari configuration variable access.
|
||||
# Map booleans, integers and strings to Python types, and back to strings.
|
||||
|
||||
def value_to_text(key, value):
|
||||
"value_to_text(key, value) -> text, convert Python type to string"
|
||||
assert(key in conftypes)
|
||||
valtype = type(value)
|
||||
if valtype == bool:
|
||||
assert(conftypes[key] == "Bool")
|
||||
if value:
|
||||
text = "TRUE"
|
||||
else:
|
||||
text = "FALSE"
|
||||
elif valtype == int:
|
||||
assert(conftypes[key] == "Int")
|
||||
text = str(value)
|
||||
else:
|
||||
assert(conftypes[key] == "String")
|
||||
if value == None:
|
||||
text = ""
|
||||
else:
|
||||
text = value
|
||||
return text
|
||||
|
||||
def text_to_value(text):
|
||||
"text_to_value(text) -> value, convert INI file values to real types"
|
||||
# bool?
|
||||
upper = text.upper()
|
||||
if upper == "FALSE":
|
||||
value = False
|
||||
elif upper == "TRUE":
|
||||
value = True
|
||||
else:
|
||||
try:
|
||||
# integer?
|
||||
value = int(text)
|
||||
except ValueError:
|
||||
# string
|
||||
value = text
|
||||
return value
|
||||
|
||||
|
||||
# ------------------------------------------------------
|
||||
# Handle INI style configuration files as used by Hatari
|
||||
|
||||
class ConfigStore:
|
||||
def __init__(self, userconfdir, defaults = {}, miss_is_error = True):
|
||||
"ConfigStore(userconfdir, fgfile[,defaults,miss_is_error])"
|
||||
self.defaults = defaults
|
||||
self.userpath = self._get_full_userpath(userconfdir)
|
||||
self.miss_is_error = miss_is_error
|
||||
|
||||
def _get_full_userpath(self, leafdir):
|
||||
"get_userpath(leafdir) -> config file default save path from HOME, CWD or their subdir"
|
||||
# user's hatari.cfg can be in home or current work dir,
|
||||
# current dir is used only if $HOME fails
|
||||
for path in (os.getenv("HOME"), os.getenv("HOMEPATH"), os.getcwd()):
|
||||
if path and os.path.exists(path) and os.path.isdir(path):
|
||||
if leafdir:
|
||||
hpath = "%s%c%s" % (path, os.path.sep, leafdir)
|
||||
if os.path.exists(hpath) and os.path.isdir(hpath):
|
||||
return hpath
|
||||
return path
|
||||
return None
|
||||
|
||||
def get_filepath(self, filename):
|
||||
"get_filepath(filename) -> return correct full path to config file"
|
||||
# user config has preference over system one
|
||||
for path in (self.userpath, os.getenv("HATARI_SYSTEM_CONFDIR")):
|
||||
if path:
|
||||
file = "%s%c%s" % (path, os.path.sep, filename)
|
||||
if os.path.isfile(file):
|
||||
return file
|
||||
# writing needs path name although it's missing for reading
|
||||
return "%s%c%s" % (self.userpath, os.path.sep, filename)
|
||||
|
||||
def load(self, path):
|
||||
"load(path) -> load given configuration file"
|
||||
if os.path.isfile(path):
|
||||
sections = self._read(path)
|
||||
if sections:
|
||||
self.sections = sections
|
||||
else:
|
||||
print("ERROR: configuration file loading failed!")
|
||||
return
|
||||
else:
|
||||
print("WARNING: configuration file missing!")
|
||||
if self.defaults:
|
||||
print("-> using dummy 'defaults'.")
|
||||
self.sections = self.defaults
|
||||
self.path = path
|
||||
self.cfgfile = os.path.basename(path)
|
||||
self.original = self.get_checkpoint()
|
||||
self.changed = False
|
||||
|
||||
def is_loaded(self):
|
||||
"is_loaded() -> True if configuration loading succeeded"
|
||||
if self.sections:
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_path(self):
|
||||
"get_path() -> configuration file path"
|
||||
return self.path
|
||||
|
||||
def _read(self, path):
|
||||
"_read(path) -> (all keys, section2key mappings)"
|
||||
print("Reading configuration file '%s'..." % path)
|
||||
config = open(path, "r")
|
||||
if not config:
|
||||
return ({}, {})
|
||||
name = "[_orphans_]"
|
||||
seckeys = {}
|
||||
sections = {}
|
||||
for line in config.readlines():
|
||||
line = line.strip()
|
||||
if not line or line[0] == '#':
|
||||
continue
|
||||
if line[0] == '[':
|
||||
if line in sections:
|
||||
print("WARNING: section '%s' twice in configuration" % line)
|
||||
if seckeys:
|
||||
sections[name] = seckeys
|
||||
seckeys = {}
|
||||
name = line
|
||||
continue
|
||||
if line.find('=') < 0:
|
||||
print("WARNING: line without key=value pair:\n%s" % line)
|
||||
continue
|
||||
key, text = [string.strip() for string in line.split('=')]
|
||||
seckeys[key] = text_to_value(text)
|
||||
if seckeys:
|
||||
sections[name] = seckeys
|
||||
return sections
|
||||
|
||||
def get_checkpoint(self):
|
||||
"get_checkpoint() -> checkpoint, get the state of variables at this point"
|
||||
checkpoint = {}
|
||||
for section in self.sections.keys():
|
||||
checkpoint[section] = self.sections[section].copy()
|
||||
return checkpoint
|
||||
|
||||
def get_checkpoint_changes(self, checkpoint):
|
||||
"get_checkpoint_changes() -> list of (key, value) pairs for later changes"
|
||||
changed = []
|
||||
if not self.changed:
|
||||
return changed
|
||||
for section in self.sections.keys():
|
||||
if section not in checkpoint:
|
||||
for key, value in self.sections[section].items():
|
||||
changed.append((key, value))
|
||||
continue
|
||||
for key, value in self.sections[section].items():
|
||||
if (key not in checkpoint[section] or
|
||||
value != checkpoint[section][key]):
|
||||
text = value_to_text(key, value)
|
||||
changed.append(("%s.%s" % (section, key), text))
|
||||
return changed
|
||||
|
||||
def revert_to_checkpoint(self, checkpoint):
|
||||
"revert_to_checkpoint(checkpoint), revert to given checkpoint"
|
||||
self.sections = checkpoint
|
||||
|
||||
def get(self, section, key):
|
||||
return self.sections[section][key]
|
||||
|
||||
def set(self, section, key, value):
|
||||
"set(section,key,value), set given key to given section"
|
||||
if section not in self.sections:
|
||||
if self.miss_is_error:
|
||||
raise AttributeError("no section '%s'" % section)
|
||||
self.sections[section] = {}
|
||||
if key not in self.sections[section]:
|
||||
if self.miss_is_error:
|
||||
raise AttributeError("key '%s' not in section '%s'" % (key, section))
|
||||
self.sections[section][key] = value
|
||||
self.changed = True
|
||||
elif self.sections[section][key] != value:
|
||||
self.changed = True
|
||||
self.sections[section][key] = value
|
||||
|
||||
def is_changed(self):
|
||||
"is_changed() -> True if current configuration is changed"
|
||||
return self.changed
|
||||
|
||||
def get_changes(self):
|
||||
"get_changes(), return (key, value) list for each changed config option"
|
||||
return self.get_checkpoint_changes(self.original)
|
||||
|
||||
def write(self, fileobj):
|
||||
"write(fileobj), write current configuration to given file object"
|
||||
sections = list(self.sections.keys())
|
||||
sections.sort()
|
||||
for name in sections:
|
||||
fileobj.write("%s\n" % name)
|
||||
keys = list(self.sections[name].keys())
|
||||
keys.sort()
|
||||
for key in keys:
|
||||
value = value_to_text(key, self.sections[name][key])
|
||||
fileobj.write("%s = %s\n" % (key, value))
|
||||
fileobj.write("\n")
|
||||
|
||||
def save(self):
|
||||
"save() -> path, if configuration changed, save it"
|
||||
if not self.changed:
|
||||
print("No configuration changes to save, skipping")
|
||||
return None
|
||||
fileobj = None
|
||||
if self.path:
|
||||
try:
|
||||
fileobj = open(self.path, "w")
|
||||
except:
|
||||
pass
|
||||
if not fileobj:
|
||||
print("WARNING: non-existing/writable configuration file, creating a new one...")
|
||||
if not os.path.exists(self.userpath):
|
||||
os.makedirs(self.userpath)
|
||||
self.path = "%s%c%s" % (self.userpath, os.path.sep, self.cfgfile)
|
||||
fileobj = open(self.path, "w")
|
||||
if not fileobj:
|
||||
print("ERROR: opening '%s' for saving failed" % self.path)
|
||||
return None
|
||||
self.write(fileobj)
|
||||
print("Saved configuration file:", self.path)
|
||||
self.changed = False
|
||||
return self.path
|
||||
|
||||
def save_as(self, path):
|
||||
"save_as(path) -> path, save configuration to given file and select it"
|
||||
assert(path)
|
||||
if not os.path.exists(os.path.dirname(path)):
|
||||
os.makedirs(os.path.dirname(path))
|
||||
self.path = path
|
||||
self.changed = True
|
||||
return self.save()
|
||||
|
||||
def save_tmp(self, path):
|
||||
"save_tmp(path) -> path, save configuration to given file without selecting it"
|
||||
if not os.path.exists(os.path.dirname(path)):
|
||||
os.makedirs(os.path.dirname(path))
|
||||
fileobj = open(path, "w")
|
||||
if not fileobj:
|
||||
print("ERROR: opening '%s' for saving failed" % path)
|
||||
return None
|
||||
self.write(fileobj)
|
||||
print("Saved temporary configuration file:", path)
|
||||
return path
|
571
python-ui/debugui.py
Executable file
@ -0,0 +1,571 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A Debug UI for the Hatari, part of PyGtk Hatari UI
|
||||
#
|
||||
# Copyright (C) 2008-2011 by Eero Tamminen
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
import os
|
||||
# use correct version of pygtk/gtk
|
||||
import pygtk
|
||||
pygtk.require('2.0')
|
||||
import gtk
|
||||
import pango
|
||||
|
||||
from config import ConfigStore
|
||||
from uihelpers import UInfo, create_button, create_toggle, \
|
||||
create_table_dialog, table_add_entry_row, table_add_widget_row, \
|
||||
get_save_filename, FselEntry
|
||||
from dialogs import TodoDialog, ErrorDialog, AskDialog, KillDialog
|
||||
|
||||
|
||||
def dialog_apply_cb(widget, dialog):
|
||||
dialog.response(gtk.RESPONSE_APPLY)
|
||||
|
||||
|
||||
# -------------
|
||||
# Table dialogs
|
||||
|
||||
class SaveDialog:
|
||||
def __init__(self, parent):
|
||||
table, self.dialog = create_table_dialog(parent, "Save from memory", 3, 2)
|
||||
self.file = FselEntry(self.dialog)
|
||||
table_add_widget_row(table, 0, "File name:", self.file.get_container())
|
||||
self.address = table_add_entry_row(table, 1, "Save address:", 6)
|
||||
self.address.connect("activate", dialog_apply_cb, self.dialog)
|
||||
self.length = table_add_entry_row(table, 2, "Number of bytes:", 6)
|
||||
self.length.connect("activate", dialog_apply_cb, self.dialog)
|
||||
|
||||
def run(self, address):
|
||||
"run(address) -> (filename,address,length), all as strings"
|
||||
if address:
|
||||
self.address.set_text("%06X" % address)
|
||||
self.dialog.show_all()
|
||||
filename = length = None
|
||||
while 1:
|
||||
response = self.dialog.run()
|
||||
if response == gtk.RESPONSE_APPLY:
|
||||
filename = self.file.get_filename()
|
||||
address_txt = self.address.get_text()
|
||||
length_txt = self.length.get_text()
|
||||
if filename and address_txt and length_txt:
|
||||
try:
|
||||
address = int(address_txt, 16)
|
||||
except ValueError:
|
||||
ErrorDialog(self.dialog).run("address needs to be in hex")
|
||||
continue
|
||||
try:
|
||||
length = int(length_txt)
|
||||
except ValueError:
|
||||
ErrorDialog(self.dialog).run("length needs to be a number")
|
||||
continue
|
||||
if os.path.exists(filename):
|
||||
question = "File:\n%s\nexists, replace?" % filename
|
||||
if not AskDialog(self.dialog).run(question):
|
||||
continue
|
||||
break
|
||||
else:
|
||||
ErrorDialog(self.dialog).run("please fill the field(s)")
|
||||
else:
|
||||
break
|
||||
self.dialog.hide()
|
||||
return (filename, address, length)
|
||||
|
||||
|
||||
class LoadDialog:
|
||||
def __init__(self, parent):
|
||||
chooser = gtk.FileChooserButton('Select a File')
|
||||
chooser.set_local_only(True) # Hatari cannot access URIs
|
||||
chooser.set_width_chars(12)
|
||||
table, self.dialog = create_table_dialog(parent, "Load to memory", 2, 2)
|
||||
self.file = table_add_widget_row(table, 0, "File name:", chooser)
|
||||
self.address = table_add_entry_row(table, 1, "Load address:", 6)
|
||||
self.address.connect("activate", dialog_apply_cb, self.dialog)
|
||||
|
||||
def run(self, address):
|
||||
"run(address) -> (filename,address), all as strings"
|
||||
if address:
|
||||
self.address.set_text("%06X" % address)
|
||||
self.dialog.show_all()
|
||||
filename = None
|
||||
while 1:
|
||||
response = self.dialog.run()
|
||||
if response == gtk.RESPONSE_APPLY:
|
||||
filename = self.file.get_filename()
|
||||
address_txt = self.address.get_text()
|
||||
if filename and address_txt:
|
||||
try:
|
||||
address = int(address_txt, 16)
|
||||
except ValueError:
|
||||
ErrorDialog(self.dialog).run("address needs to be in hex")
|
||||
continue
|
||||
break
|
||||
else:
|
||||
ErrorDialog(self.dialog).run("please fill the field(s)")
|
||||
else:
|
||||
break
|
||||
self.dialog.hide()
|
||||
return (filename, address)
|
||||
|
||||
|
||||
class OptionsDialog:
|
||||
def __init__(self, parent):
|
||||
self.dialog = gtk.Dialog("Debugger UI options", parent,
|
||||
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
|
||||
(gtk.STOCK_APPLY, gtk.RESPONSE_APPLY,
|
||||
gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))
|
||||
|
||||
self.lines = gtk.Adjustment(0, 5, 50)
|
||||
scale = gtk.HScale(self.lines)
|
||||
scale.set_digits(0)
|
||||
|
||||
self.follow_pc = gtk.CheckButton("On stop, set address to PC")
|
||||
|
||||
vbox = self.dialog.vbox
|
||||
vbox.add(gtk.Label("Memdump/disasm lines:"))
|
||||
vbox.add(scale)
|
||||
vbox.add(self.follow_pc)
|
||||
vbox.show_all()
|
||||
|
||||
def run(self, lines, follow_pc):
|
||||
"run(lines,follow_pc) -> (lines,follow_pc)"
|
||||
self.follow_pc.set_active(follow_pc)
|
||||
self.lines.set_value(lines)
|
||||
self.dialog.show_all()
|
||||
response = self.dialog.run()
|
||||
if response == gtk.RESPONSE_APPLY:
|
||||
lines = int(self.lines.get_value())
|
||||
follow_pc = self.follow_pc.get_active()
|
||||
self.dialog.hide()
|
||||
return (lines, follow_pc)
|
||||
|
||||
|
||||
# ----------------------------------------------------
|
||||
|
||||
# constants for the other classes
|
||||
class Constants:
|
||||
# dump modes
|
||||
DISASM = 1
|
||||
MEMDUMP = 2
|
||||
REGISTERS = 3
|
||||
# move IDs
|
||||
MOVE_MIN = 1
|
||||
MOVE_MED = 2
|
||||
MOVE_MAX = 3
|
||||
|
||||
|
||||
# class for the memory address entry, view (label) and
|
||||
# the logic for memory dump modes and moving in memory
|
||||
class MemoryAddress:
|
||||
# class variables
|
||||
debug_output = None
|
||||
hatari = None
|
||||
|
||||
def __init__(self, hatariobj):
|
||||
# hatari
|
||||
self.debug_output = hatariobj.open_debug_output()
|
||||
self.hatari = hatariobj
|
||||
# widgets
|
||||
self.entry, self.memory = self.create_widgets()
|
||||
# settings
|
||||
self.dumpmode = Constants.REGISTERS
|
||||
self.follow_pc = True
|
||||
self.lines = 12
|
||||
# addresses
|
||||
self.first = None
|
||||
self.second = None
|
||||
self.last = None
|
||||
|
||||
def clear(self):
|
||||
if self.follow_pc:
|
||||
# get first address from PC when next stopped
|
||||
self.first = None
|
||||
self.second = None
|
||||
self.last = None
|
||||
|
||||
def create_widgets(self):
|
||||
entry = gtk.Entry(6)
|
||||
entry.set_width_chars(6)
|
||||
entry.connect("activate", self._entry_cb)
|
||||
memory = gtk.Label()
|
||||
mono = pango.FontDescription("monospace")
|
||||
memory.modify_font(mono)
|
||||
entry.modify_font(mono)
|
||||
return (entry, memory)
|
||||
|
||||
def _entry_cb(self, widget):
|
||||
try:
|
||||
address = int(widget.get_text(), 16)
|
||||
except ValueError:
|
||||
ErrorDialog(widget.get_toplevel()).run("invalid address")
|
||||
return
|
||||
self.dump(address)
|
||||
|
||||
def reset_entry(self):
|
||||
self.entry.set_text("%06X" % self.first)
|
||||
|
||||
def get(self):
|
||||
return self.first
|
||||
|
||||
def get_memory_label(self):
|
||||
return self.memory
|
||||
|
||||
def get_address_entry(self):
|
||||
return self.entry
|
||||
|
||||
def get_follow_pc(self):
|
||||
return self.follow_pc
|
||||
|
||||
def set_follow_pc(self, follow_pc):
|
||||
self.follow_pc = follow_pc
|
||||
|
||||
def get_lines(self):
|
||||
return self.lines
|
||||
|
||||
def set_lines(self, lines):
|
||||
self.lines = lines
|
||||
|
||||
def set_dumpmode(self, mode):
|
||||
self.dumpmode = mode
|
||||
self.dump()
|
||||
|
||||
def dump(self, address = None, move_idx = 0):
|
||||
if self.dumpmode == Constants.REGISTERS:
|
||||
output = self._get_registers()
|
||||
self.memory.set_label("".join(output))
|
||||
return
|
||||
|
||||
if not address:
|
||||
if not self.first:
|
||||
self._get_registers()
|
||||
address = self.first
|
||||
|
||||
if not address:
|
||||
print("ERROR: address needed")
|
||||
return
|
||||
|
||||
if self.dumpmode == Constants.MEMDUMP:
|
||||
output = self._get_memdump(address, move_idx)
|
||||
elif self.dumpmode == Constants.DISASM:
|
||||
output = self._get_disasm(address, move_idx)
|
||||
else:
|
||||
print("ERROR: unknown dumpmode:", self.dumpmode)
|
||||
return
|
||||
self.memory.set_label("".join(output))
|
||||
if move_idx:
|
||||
self.reset_entry()
|
||||
|
||||
def _get_registers(self):
|
||||
self.hatari.debug_command("r")
|
||||
output = self.hatari.get_lines(self.debug_output)
|
||||
if not self.first:
|
||||
# 2nd last line has first PC in 1st column, last line next PC in 2nd column
|
||||
self.second = int(output[-1][output[-1].find(":")+2:], 16)
|
||||
# OldUAE CPU core has ':' in both
|
||||
offset = output[-2].find(":")
|
||||
if offset < 0:
|
||||
# WinUAE CPU core only in one
|
||||
offset = output[-2].find(" ")
|
||||
if offset < 0:
|
||||
print("ERROR: unable to parse register dump line:\n\t'%s'", output[-2])
|
||||
return output
|
||||
self.first = int(output[-2][:offset], 16)
|
||||
self.reset_entry()
|
||||
return output
|
||||
|
||||
def _get_memdump(self, address, move_idx):
|
||||
linewidth = 16
|
||||
screenful = self.lines*linewidth
|
||||
# no move, left/right, up/down, page up/down (no overlap)
|
||||
offsets = [0, 2, linewidth, screenful]
|
||||
offset = offsets[abs(move_idx)]
|
||||
if move_idx < 0:
|
||||
address -= offset
|
||||
else:
|
||||
address += offset
|
||||
self._set_clamped(address, address+screenful)
|
||||
self.hatari.debug_command("m $%06x-$%06x" % (self.first, self.last))
|
||||
# get & set debugger command results
|
||||
output = self.hatari.get_lines(self.debug_output)
|
||||
self.second = address + linewidth
|
||||
return output
|
||||
|
||||
def _get_disasm(self, address, move_idx):
|
||||
# TODO: uses brute force i.e. ask for more lines that user has
|
||||
# requested to be sure that the window is filled, assuming
|
||||
# 6 bytes is largest possible instruction+args size
|
||||
# (I don't remember anymore my m68k asm...)
|
||||
screenful = 6*self.lines
|
||||
# no move, left/right, up/down, page up/down
|
||||
offsets = [0, 2, 4, screenful]
|
||||
offset = offsets[abs(move_idx)]
|
||||
# force one line of overlap in page up/down
|
||||
if move_idx < 0:
|
||||
address -= offset
|
||||
if address < 0:
|
||||
address = 0
|
||||
if move_idx == -Constants.MOVE_MAX and self.second:
|
||||
screenful = self.second - address
|
||||
else:
|
||||
if move_idx == Constants.MOVE_MED and self.second:
|
||||
address = self.second
|
||||
elif move_idx == Constants.MOVE_MAX and self.last:
|
||||
address = self.last
|
||||
else:
|
||||
address += offset
|
||||
self._set_clamped(address, address+screenful)
|
||||
self.hatari.debug_command("d $%06x-$%06x" % (self.first, self.last))
|
||||
# get & set debugger command results
|
||||
output = self.hatari.get_lines(self.debug_output)
|
||||
# cut output to desired length and check new addresses
|
||||
if len(output) > self.lines:
|
||||
if move_idx < 0:
|
||||
output = output[-self.lines:]
|
||||
else:
|
||||
output = output[:self.lines]
|
||||
# with disasm need to re-get the addresses from the output
|
||||
self.first = int(output[0][1:output[0].find(":")], 16)
|
||||
self.second = int(output[1][1:output[1].find(":")], 16)
|
||||
self.last = int(output[-1][1:output[-1].find(":")], 16)
|
||||
return output
|
||||
|
||||
def _set_clamped(self, first, last):
|
||||
"set_clamped(first,last), clamp addresses to valid address range and set them"
|
||||
assert(first < last)
|
||||
if first < 0:
|
||||
last = last-first
|
||||
first = 0
|
||||
if last > 0xffffff:
|
||||
first = 0xffffff - (last-first)
|
||||
last = 0xffffff
|
||||
self.first = first
|
||||
self.last = last
|
||||
|
||||
|
||||
# the Hatari debugger UI class and methods
|
||||
class HatariDebugUI:
|
||||
|
||||
def __init__(self, hatariobj, do_destroy = False):
|
||||
self.address = MemoryAddress(hatariobj)
|
||||
self.hatari = hatariobj
|
||||
# set when needed/created
|
||||
self.dialog_load = None
|
||||
self.dialog_save = None
|
||||
self.dialog_options = None
|
||||
# set when UI created
|
||||
self.keys = None
|
||||
self.stop_button = None
|
||||
# set on option load
|
||||
self.config = None
|
||||
self.load_options()
|
||||
# UI initialization/creation
|
||||
self.window = self.create_ui("Hatari Debug UI", do_destroy)
|
||||
|
||||
def create_ui(self, title, do_destroy):
|
||||
# buttons at top
|
||||
hbox1 = gtk.HBox()
|
||||
self.create_top_buttons(hbox1)
|
||||
|
||||
# disasm/memory dump at the middle
|
||||
align = gtk.Alignment()
|
||||
# top, bottom, left, right padding
|
||||
align.set_padding(8, 0, 8, 8)
|
||||
align.add(self.address.get_memory_label())
|
||||
|
||||
# buttons at bottom
|
||||
hbox2 = gtk.HBox()
|
||||
self.create_bottom_buttons(hbox2)
|
||||
|
||||
# their container
|
||||
vbox = gtk.VBox()
|
||||
vbox.pack_start(hbox1, False)
|
||||
vbox.pack_start(align, True, True)
|
||||
vbox.pack_start(hbox2, False)
|
||||
|
||||
# and the window for all of this
|
||||
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
|
||||
window.set_events(gtk.gdk.KEY_RELEASE_MASK)
|
||||
window.connect("key_release_event", self.key_event_cb)
|
||||
if do_destroy:
|
||||
window.connect("delete_event", self.quit)
|
||||
else:
|
||||
window.connect("delete_event", self.hide)
|
||||
window.set_icon_from_file(UInfo.icon)
|
||||
window.set_title(title)
|
||||
window.add(vbox)
|
||||
return window
|
||||
|
||||
def create_top_buttons(self, box):
|
||||
self.stop_button = create_toggle("Stop", self.stop_cb)
|
||||
box.add(self.stop_button)
|
||||
|
||||
monitor = create_button("Monitor...", self.monitor_cb)
|
||||
box.add(monitor)
|
||||
|
||||
buttons = (
|
||||
("<<<", "Page_Up", -Constants.MOVE_MAX),
|
||||
("<<", "Up", -Constants.MOVE_MED),
|
||||
("<", "Left", -Constants.MOVE_MIN),
|
||||
(">", "Right", Constants.MOVE_MIN),
|
||||
(">>", "Down", Constants.MOVE_MED),
|
||||
(">>>", "Page_Down", Constants.MOVE_MAX)
|
||||
)
|
||||
self.keys = {}
|
||||
for label, keyname, offset in buttons:
|
||||
button = create_button(label, self.set_address_offset, offset)
|
||||
keyval = gtk.gdk.keyval_from_name(keyname)
|
||||
self.keys[keyval] = offset
|
||||
box.add(button)
|
||||
|
||||
# to middle of <<>> buttons
|
||||
address_entry = self.address.get_address_entry()
|
||||
box.pack_start(address_entry, False)
|
||||
box.reorder_child(address_entry, 5)
|
||||
|
||||
def create_bottom_buttons(self, box):
|
||||
radios = (
|
||||
("Registers", Constants.REGISTERS),
|
||||
("Memdump", Constants.MEMDUMP),
|
||||
("Disasm", Constants.DISASM)
|
||||
)
|
||||
group = None
|
||||
for label, mode in radios:
|
||||
button = gtk.RadioButton(group, label)
|
||||
if not group:
|
||||
group = button
|
||||
button.connect("toggled", self.dumpmode_cb, mode)
|
||||
button.unset_flags(gtk.CAN_FOCUS)
|
||||
box.add(button)
|
||||
group.set_active(True)
|
||||
|
||||
dialogs = (
|
||||
("Memload...", self.memload_cb),
|
||||
("Memsave...", self.memsave_cb),
|
||||
("Options...", self.options_cb)
|
||||
)
|
||||
for label, cb in dialogs:
|
||||
button = create_button(label, cb)
|
||||
box.add(button)
|
||||
|
||||
def stop_cb(self, widget):
|
||||
if widget.get_active():
|
||||
self.hatari.pause()
|
||||
self.address.clear()
|
||||
self.address.dump()
|
||||
else:
|
||||
self.hatari.unpause()
|
||||
|
||||
def dumpmode_cb(self, widget, mode):
|
||||
if widget.get_active():
|
||||
self.address.set_dumpmode(mode)
|
||||
|
||||
def key_event_cb(self, widget, event):
|
||||
if event.keyval in self.keys:
|
||||
self.address.dump(None, self.keys[event.keyval])
|
||||
|
||||
def set_address_offset(self, widget, move_idx):
|
||||
self.address.dump(None, move_idx)
|
||||
|
||||
def monitor_cb(self, widget):
|
||||
TodoDialog(self.window).run("add register / memory address range monitor window.")
|
||||
|
||||
def memload_cb(self, widget):
|
||||
if not self.dialog_load:
|
||||
self.dialog_load = LoadDialog(self.window)
|
||||
(filename, address) = self.dialog_load.run(self.address.get())
|
||||
if filename and address:
|
||||
self.hatari.debug_command("l %s $%06x" % (filename, address))
|
||||
|
||||
def memsave_cb(self, widget):
|
||||
if not self.dialog_save:
|
||||
self.dialog_save = SaveDialog(self.window)
|
||||
(filename, address, length) = self.dialog_save.run(self.address.get())
|
||||
if filename and address and length:
|
||||
self.hatari.debug_command("s %s $%06x $%06x" % (filename, address, length))
|
||||
|
||||
def options_cb(self, widget):
|
||||
if not self.dialog_options:
|
||||
self.dialog_options = OptionsDialog(self.window)
|
||||
old_lines = self.config.get("[General]", "nLines")
|
||||
old_follow_pc = self.config.get("[General]", "bFollowPC")
|
||||
lines, follow_pc = self.dialog_options.run(old_lines, old_follow_pc)
|
||||
if lines != old_lines:
|
||||
self.config.set("[General]", "nLines", lines)
|
||||
self.address.set_lines(lines)
|
||||
if follow_pc != old_follow_pc:
|
||||
self.config.set("[General]", "bFollowPC", follow_pc)
|
||||
self.address.set_follow_pc(follow_pc)
|
||||
|
||||
def load_options(self):
|
||||
# TODO: move config to MemoryAddress class?
|
||||
# (depends on how monitoring of addresses should work)
|
||||
lines = self.address.get_lines()
|
||||
follow_pc = self.address.get_follow_pc()
|
||||
miss_is_error = False # needed for adding windows
|
||||
defaults = {
|
||||
"[General]": {
|
||||
"nLines": lines,
|
||||
"bFollowPC": follow_pc
|
||||
}
|
||||
}
|
||||
userconfdir = ".hatari"
|
||||
config = ConfigStore(userconfdir, defaults, miss_is_error)
|
||||
configpath = config.get_filepath("debugui.cfg")
|
||||
config.load(configpath) # set defaults
|
||||
try:
|
||||
self.address.set_lines(config.get("[General]", "nLines"))
|
||||
self.address.set_follow_pc(config.get("[General]", "bFollowPC"))
|
||||
except (KeyError, AttributeError):
|
||||
ErrorDialog(None).run("Debug UI configuration mismatch!\nTry again after removing: '%s'." % configpath)
|
||||
self.config = config
|
||||
|
||||
def save_options(self):
|
||||
self.config.save()
|
||||
|
||||
def show(self):
|
||||
self.stop_button.set_active(True)
|
||||
self.window.show_all()
|
||||
self.window.deiconify()
|
||||
|
||||
def hide(self, widget, arg):
|
||||
self.window.hide()
|
||||
self.stop_button.set_active(False)
|
||||
self.save_options()
|
||||
return True
|
||||
|
||||
def quit(self, widget, arg):
|
||||
KillDialog(self.window).run(self.hatari)
|
||||
gtk.main_quit()
|
||||
|
||||
|
||||
def main():
|
||||
import sys
|
||||
from hatari import Hatari
|
||||
hatariobj = Hatari()
|
||||
if len(sys.argv) > 1:
|
||||
if sys.argv[1] in ("-h", "--help"):
|
||||
print("usage: %s [hatari options]" % os.path.basename(sys.argv[0]))
|
||||
return
|
||||
args = sys.argv[1:]
|
||||
else:
|
||||
args = None
|
||||
hatariobj.run(args)
|
||||
|
||||
info = UInfo()
|
||||
debugui = HatariDebugUI(hatariobj, True)
|
||||
debugui.window.show_all()
|
||||
gtk.main()
|
||||
debugui.save_options()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
1024
python-ui/dialogs.py
Normal file
32
python-ui/gentypes.py
Executable file
@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Utility to generate from Hatari C-code Python code for mapping
|
||||
# Hatari configuration variable names and types of those variables.
|
||||
#
|
||||
# Copyright (C) 2012 by Eero Tamminen
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
import os, re, sys
|
||||
|
||||
# match first two items (variable name and type) from lines like:
|
||||
# { "bConfirmQuit", Bool_Tag, &ConfigureParams.Log.bConfirmQuit }
|
||||
reg = re.compile("\"([a-zA-Z0-9_]+)\",\s*([BIS][a-z]+)_Tag\s*,")
|
||||
|
||||
print "# content generated by %s" % os.path.basename(sys.argv[0])
|
||||
print "conftypes = {"
|
||||
|
||||
for line in sys.stdin.readlines():
|
||||
match = reg.search(line)
|
||||
if match:
|
||||
print """ "%s": "%s",""" % match.groups()
|
||||
|
||||
print "}"
|
BIN
python-ui/hatari-icon.png
Normal file
After Width: | Height: | Size: 505 B |
BIN
python-ui/hatari-logo.png
Normal file
After Width: | Height: | Size: 24 KiB |
903
python-ui/hatari.py
Normal file
@ -0,0 +1,903 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Classes for Hatari emulator instance and mapping its congfiguration
|
||||
# variables with its command line option.
|
||||
#
|
||||
# Copyright (C) 2008-2015 by Eero Tamminen
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import signal
|
||||
import socket
|
||||
import select
|
||||
from config import ConfigStore
|
||||
|
||||
|
||||
# Running Hatari instance
|
||||
class Hatari:
|
||||
"running hatari instance and methods for communicating with it"
|
||||
basepath = "/tmp/hatari-ui-" + str(os.getpid())
|
||||
logpath = basepath + ".log"
|
||||
tracepath = basepath + ".trace"
|
||||
debugpath = basepath + ".debug"
|
||||
controlpath = basepath + ".socket"
|
||||
server = None # singleton due to path being currently one per user
|
||||
|
||||
def __init__(self, hataribin = None):
|
||||
# collect hatari process zombies without waitpid()
|
||||
signal.signal(signal.SIGCHLD, signal.SIG_IGN)
|
||||
if hataribin:
|
||||
self.hataribin = hataribin
|
||||
else:
|
||||
self.hataribin = "hatari"
|
||||
self._create_server()
|
||||
self.control = None
|
||||
self.paused = False
|
||||
self.pid = 0
|
||||
|
||||
def is_compatible(self):
|
||||
"check Hatari compatibility and return error string if it's not"
|
||||
error = "Hatari not found or it doesn't support the required --control-socket option!"
|
||||
pipe = os.popen(self.hataribin + " -h")
|
||||
for line in pipe.readlines():
|
||||
if line.find("--control-socket") >= 0:
|
||||
error = None
|
||||
break
|
||||
try:
|
||||
pipe.close()
|
||||
except IOError:
|
||||
pass
|
||||
return error
|
||||
|
||||
def save_config(self):
|
||||
os.popen(self.hataribin + " --saveconfig")
|
||||
|
||||
def _create_server(self):
|
||||
if self.server:
|
||||
return
|
||||
self.server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||
if os.path.exists(self.controlpath):
|
||||
os.unlink(self.controlpath)
|
||||
self.server.bind(self.controlpath)
|
||||
self.server.listen(1)
|
||||
|
||||
def _send_message(self, msg):
|
||||
if self.control:
|
||||
self.control.send(msg)
|
||||
return True
|
||||
else:
|
||||
print("ERROR: no Hatari (control socket)")
|
||||
return False
|
||||
|
||||
def change_option(self, option):
|
||||
"change_option(option), changes given Hatari cli option"
|
||||
return self._send_message("hatari-option %s\n" % option)
|
||||
|
||||
def set_path(self, key, path):
|
||||
"set_path(key, path), sets path with given key"
|
||||
return self._send_message("hatari-path %s %s\n" % (key, path))
|
||||
|
||||
def set_device(self, device, enabled):
|
||||
# needed because CLI options cannot disable devices, only enable
|
||||
"set_path(device, enabled), sets whether given device is enabled or not"
|
||||
if enabled:
|
||||
return self._send_message("hatari-enable %s\n" % device)
|
||||
else:
|
||||
return self._send_message("hatari-disable %s\n" % device)
|
||||
|
||||
def trigger_shortcut(self, shortcut):
|
||||
"trigger_shortcut(shortcut), triggers given Hatari (keyboard) shortcut"
|
||||
return self._send_message("hatari-shortcut %s\n" % shortcut)
|
||||
|
||||
def insert_event(self, event):
|
||||
"insert_event(event), synthetizes given key/mouse Atari event"
|
||||
return self._send_message("hatari-event %s\n" % event)
|
||||
|
||||
def debug_command(self, cmd):
|
||||
"debug_command(command), runs given Hatari debugger command"
|
||||
return self._send_message("hatari-debug %s\n" % cmd)
|
||||
|
||||
def pause(self):
|
||||
"pause(), pauses Hatari emulation"
|
||||
return self._send_message("hatari-stop\n")
|
||||
|
||||
def unpause(self):
|
||||
"unpause(), continues Hatari emulation"
|
||||
return self._send_message("hatari-cont\n")
|
||||
|
||||
def _open_output_file(self, hataricommand, option, path):
|
||||
if os.path.exists(path):
|
||||
os.unlink(path)
|
||||
# TODO: why fifo doesn't work properly (blocks forever on read or
|
||||
# reads only byte at the time and stops after first newline)?
|
||||
#os.mkfifo(path)
|
||||
#raw_input("attach strace now, then press Enter\n")
|
||||
|
||||
# ask Hatari to open/create the requested output file...
|
||||
hataricommand("%s %s" % (option, path))
|
||||
wait = 0.025
|
||||
# ...and wait for it to appear before returning it
|
||||
for i in range(0, 8):
|
||||
time.sleep(wait)
|
||||
if os.path.exists(path):
|
||||
return open(path, "r")
|
||||
wait += wait
|
||||
return None
|
||||
|
||||
def open_debug_output(self):
|
||||
"open_debug_output() -> file, opens Hatari debugger output file"
|
||||
return self._open_output_file(self.debug_command, "f", self.debugpath)
|
||||
|
||||
def open_trace_output(self):
|
||||
"open_trace_output() -> file, opens Hatari tracing output file"
|
||||
return self._open_output_file(self.change_option, "--trace-file", self.tracepath)
|
||||
|
||||
def open_log_output(self):
|
||||
"open_trace_output() -> file, opens Hatari debug log file"
|
||||
return self._open_output_file(self.change_option, "--log-file", self.logpath)
|
||||
|
||||
def get_lines(self, fileobj):
|
||||
"get_lines(file) -> list of lines readable from given Hatari output file"
|
||||
# wait until data is available, then wait for some more
|
||||
# and only then the data can be read, otherwise its old
|
||||
print("Request&wait data from Hatari...")
|
||||
select.select([fileobj], [], [])
|
||||
time.sleep(0.1)
|
||||
print("...read the data lines")
|
||||
lines = fileobj.readlines()
|
||||
print("".join(lines))
|
||||
return lines
|
||||
|
||||
def enable_embed_info(self):
|
||||
"enable_embed_info(), request embedded Hatari window ID change information"
|
||||
self._send_message("hatari-embed-info\n")
|
||||
|
||||
def get_embed_info(self):
|
||||
"get_embed_info() -> (width, height), get embedded Hatari window size"
|
||||
width, height = self.control.recv(12).split("x")
|
||||
return (int(width), int(height))
|
||||
|
||||
def get_control_socket(self):
|
||||
"get_control_socket() -> socket which can be checked for embed ID changes"
|
||||
return self.control
|
||||
|
||||
def is_running(self):
|
||||
"is_running() -> bool, True if Hatari is running, False otherwise"
|
||||
if not self.pid:
|
||||
return False
|
||||
try:
|
||||
os.waitpid(self.pid, os.WNOHANG)
|
||||
except OSError as value:
|
||||
print("Hatari PID %d had exited in the meanwhile:\n\t%s" % (self.pid, value))
|
||||
self.pid = 0
|
||||
if self.control:
|
||||
self.control.close()
|
||||
self.control = None
|
||||
return False
|
||||
return True
|
||||
|
||||
def run(self, extra_args = None, parent_win = None):
|
||||
"run([parent window][,embedding args]), runs Hatari"
|
||||
# if parent_win given, embed Hatari to it
|
||||
pid = os.fork()
|
||||
if pid < 0:
|
||||
print("ERROR: fork()ing Hatari failed!")
|
||||
return
|
||||
if pid:
|
||||
# in parent
|
||||
self.pid = pid
|
||||
if self.server:
|
||||
print("WAIT hatari to connect to control socket...")
|
||||
(self.control, addr) = self.server.accept()
|
||||
print("connected!")
|
||||
else:
|
||||
# child runs Hatari
|
||||
env = os.environ
|
||||
if parent_win:
|
||||
self._set_embed_env(env, parent_win)
|
||||
# callers need to take care of confirming quitting
|
||||
args = [self.hataribin, "--confirm-quit", "off"]
|
||||
if self.server:
|
||||
args += ["--control-socket", self.controlpath]
|
||||
if extra_args:
|
||||
args += extra_args
|
||||
print("RUN:", args)
|
||||
os.execvpe(self.hataribin, args, env)
|
||||
|
||||
def _set_embed_env(self, env, parent_win):
|
||||
if sys.platform == 'win32':
|
||||
win_id = parent_win.handle
|
||||
else:
|
||||
win_id = parent_win.xid
|
||||
# tell SDL to use given widget's window
|
||||
#env["SDL_WINDOWID"] = str(win_id)
|
||||
|
||||
# above is broken: when SDL uses a window it hasn't created itself,
|
||||
# it for some reason doesn't listen to any events delivered to that
|
||||
# window nor implements XEMBED protocol to get them in a way most
|
||||
# friendly to embedder:
|
||||
# http://standards.freedesktop.org/xembed-spec/latest/
|
||||
#
|
||||
# Instead we tell hatari to reparent itself after creating
|
||||
# its own window into this program widget window
|
||||
env["PARENT_WIN_ID"] = str(win_id)
|
||||
|
||||
def kill(self):
|
||||
"kill(), kill Hatari if it's running"
|
||||
if self.is_running():
|
||||
os.kill(self.pid, signal.SIGKILL)
|
||||
print("killed hatari with PID %d" % self.pid)
|
||||
self.pid = 0
|
||||
if self.control:
|
||||
self.control.close()
|
||||
self.control = None
|
||||
|
||||
|
||||
# Mapping of requested values both to Hatari configuration
|
||||
# and command line options.
|
||||
#
|
||||
# By default this doesn't allow setting any other configuration
|
||||
# variables than the ones that were read from the configuration
|
||||
# file i.e. you get an exception if configuration variables
|
||||
# don't match to current Hatari. So before using this the current
|
||||
# Hatari configuration should have been saved at least once.
|
||||
#
|
||||
# Because of some inconsistencies in the values (see e.g. sound),
|
||||
# this cannot just do these according to some mapping table, but
|
||||
# it needs actual method for (each) setting.
|
||||
class HatariConfigMapping(ConfigStore):
|
||||
_paths = {
|
||||
"memauto": ("[Memory]", "szAutoSaveFileName", "Automatic memory snapshot"),
|
||||
"memsave": ("[Memory]", "szMemoryCaptureFileName", "Manual memory snapshot"),
|
||||
"midiin": ("[Midi]", "sMidiInFileName", "Midi input"),
|
||||
"midiout": ("[Midi]", "sMidiOutFileName", "Midi output"),
|
||||
"rs232in": ("[RS232]", "szInFileName", "RS232 I/O input"),
|
||||
"rs232out": ("[RS232]", "szOutFileName", "RS232 I/O output"),
|
||||
"printout": ("[Printer]", "szPrintToFileName", "Printer output"),
|
||||
"soundout": ("[Sound]", "szYMCaptureFileName", "Sound output")
|
||||
}
|
||||
"access methods to Hatari configuration file variables and command line options"
|
||||
def __init__(self, hatari):
|
||||
userconfdir = ".hatari"
|
||||
ConfigStore.__init__(self, userconfdir)
|
||||
conffilename = "hatari.cfg"
|
||||
self.load(self.get_filepath(conffilename))
|
||||
|
||||
self._hatari = hatari
|
||||
self._lock_updates = False
|
||||
self._desktop_w = 0
|
||||
self._desktop_h = 0
|
||||
self._options = []
|
||||
|
||||
def validate(self):
|
||||
"exception is thrown if the loaded configuration isn't compatible"
|
||||
for method in dir(self):
|
||||
if '_' not in method:
|
||||
continue
|
||||
# check class getters
|
||||
starts = method[:method.find("_")]
|
||||
if starts != "get":
|
||||
continue
|
||||
# but ignore getters for other things than config
|
||||
ends = method[method.rfind("_")+1:]
|
||||
if ends in ("types", "names", "values", "changes", "checkpoint", "filepath"):
|
||||
continue
|
||||
if ends in ("floppy", "joystick"):
|
||||
# use port '0' for checks
|
||||
getattr(self, method)(0)
|
||||
else:
|
||||
getattr(self, method)()
|
||||
|
||||
def _change_option(self, option, quoted = None):
|
||||
"handle option changing, and quote spaces for quoted part of it"
|
||||
if quoted:
|
||||
option = "%s %s" % (option, quoted.replace(" ", "\\ "))
|
||||
if self._lock_updates:
|
||||
self._options.append(option)
|
||||
else:
|
||||
self._hatari.change_option(option)
|
||||
|
||||
def lock_updates(self):
|
||||
"lock_updates(), collect Hatari configuration changes"
|
||||
self._lock_updates = True
|
||||
|
||||
def flush_updates(self):
|
||||
"flush_updates(), apply collected Hatari configuration changes"
|
||||
self._lock_updates = False
|
||||
if not self._options:
|
||||
return
|
||||
self._hatari.change_option(" ".join(self._options))
|
||||
self._options = []
|
||||
|
||||
# ------------ paths ---------------
|
||||
def get_paths(self):
|
||||
paths = []
|
||||
for key, item in self._paths.items():
|
||||
paths.append((key, self.get(item[0], item[1]), item[2]))
|
||||
return paths
|
||||
|
||||
def set_paths(self, paths):
|
||||
for key, path in paths:
|
||||
self.set(self._paths[key][0], self._paths[key][1], path)
|
||||
self._hatari.set_path(key, path)
|
||||
|
||||
# ------------ midi ---------------
|
||||
def get_midi(self):
|
||||
return self.get("[Midi]", "bEnableMidi")
|
||||
|
||||
def set_midi(self, value):
|
||||
self.set("[Midi]", "bEnableMidi", value)
|
||||
self._hatari.set_device("midi", value)
|
||||
|
||||
# ------------ printer ---------------
|
||||
def get_printer(self):
|
||||
return self.get("[Printer]", "bEnablePrinting")
|
||||
|
||||
def set_printer(self, value):
|
||||
self.set("[Printer]", "bEnablePrinting", value)
|
||||
self._hatari.set_device("printer", value)
|
||||
|
||||
# ------------ RS232 ---------------
|
||||
def get_rs232(self):
|
||||
return self.get("[RS232]", "bEnableRS232")
|
||||
|
||||
def set_rs232(self, value):
|
||||
self.set("[RS232]", "bEnableRS232", value)
|
||||
self._hatari.set_device("rs232", value)
|
||||
|
||||
# ------------ machine ---------------
|
||||
def get_machine_types(self):
|
||||
return ("ST", "STE", "TT", "Falcon")
|
||||
|
||||
def get_machine(self):
|
||||
return self.get("[System]", "nMachineType")
|
||||
|
||||
def set_machine(self, value):
|
||||
self.set("[System]", "nMachineType", value)
|
||||
self._change_option("--machine %s" % ("st", "ste", "tt", "falcon")[value])
|
||||
|
||||
# ------------ CPU level ---------------
|
||||
def get_cpulevel_types(self):
|
||||
return ("68000", "68010", "68020", "68EC030+FPU", "68040")
|
||||
|
||||
def get_cpulevel(self):
|
||||
return self.get("[System]", "nCpuLevel")
|
||||
|
||||
def set_cpulevel(self, value):
|
||||
self.set("[System]", "nCpuLevel", value)
|
||||
self._change_option("--cpulevel %d" % value)
|
||||
|
||||
# ------------ CPU clock ---------------
|
||||
def get_cpuclock_types(self):
|
||||
return ("8 MHz", "16 MHz", "32 MHz")
|
||||
|
||||
def get_cpuclock(self):
|
||||
clocks = {8:0, 16: 1, 32:2}
|
||||
return clocks[self.get("[System]", "nCpuFreq")]
|
||||
|
||||
def set_cpuclock(self, value):
|
||||
clocks = [8, 16, 32]
|
||||
if value < 0 or value > 2:
|
||||
print("WARNING: CPU clock idx %d, clock fixed to 8 Mhz" % value)
|
||||
value = 8
|
||||
else:
|
||||
value = clocks[value]
|
||||
self.set("[System]", "nCpuFreq", value)
|
||||
self._change_option("--cpuclock %d" % value)
|
||||
|
||||
# ------------ DSP type ---------------
|
||||
def get_dsp_types(self):
|
||||
return ("None", "Dummy", "Emulated")
|
||||
|
||||
def get_dsp(self):
|
||||
return self.get("[System]", "nDSPType")
|
||||
|
||||
def set_dsp(self, value):
|
||||
self.set("[System]", "nDSPType", value)
|
||||
self._change_option("--dsp %s" % ("none", "dummy", "emu")[value])
|
||||
|
||||
# ------------ compatible ---------------
|
||||
def get_compatible(self):
|
||||
return self.get("[System]", "bCompatibleCpu")
|
||||
|
||||
def set_compatible(self, value):
|
||||
self.set("[System]", "bCompatibleCpu", value)
|
||||
self._change_option("--compatible %s" % str(value))
|
||||
|
||||
# ------------ Timer-D ---------------
|
||||
def get_timerd(self):
|
||||
return self.get("[System]", "bPatchTimerD")
|
||||
|
||||
def set_timerd(self, value):
|
||||
self.set("[System]", "bPatchTimerD", value)
|
||||
self._change_option("--timer-d %s" % str(value))
|
||||
|
||||
# ------------ RTC ---------------
|
||||
def get_rtc(self):
|
||||
return self.get("[System]", "bRealTimeClock")
|
||||
|
||||
def set_rtc(self, value):
|
||||
self.set("[System]", "bRealTimeClock", value)
|
||||
self._change_option("--rtc %s" % str(value))
|
||||
|
||||
# ------------ fastforward ---------------
|
||||
def get_fastforward(self):
|
||||
return self.get("[System]", "bFastForward")
|
||||
|
||||
def set_fastforward(self, value):
|
||||
self.set("[System]", "bFastForward", value)
|
||||
self._change_option("--fast-forward %s" % str(value))
|
||||
|
||||
# ------------ sound ---------------
|
||||
def get_sound_values(self):
|
||||
# 48kHz, 44.1kHz and STE/TT/Falcon DMA 50066Hz divisable values
|
||||
return ("6000", "6258", "8000", "11025", "12000", "12517",
|
||||
"16000", "22050", "24000", "25033", "32000",
|
||||
"44100", "48000", "50066")
|
||||
|
||||
def get_sound(self):
|
||||
enabled = self.get("[Sound]", "bEnableSound")
|
||||
hz = str(self.get("[Sound]", "nPlaybackFreq"))
|
||||
idx = self.get_sound_values().index(hz)
|
||||
return (enabled, idx)
|
||||
|
||||
def set_sound(self, enabled, idx):
|
||||
# map get_sound_values() index to Hatari config
|
||||
hz = self.get_sound_values()[idx]
|
||||
self.set("[Sound]", "nPlaybackFreq", int(hz))
|
||||
self.set("[Sound]", "bEnableSound", enabled)
|
||||
# and to cli option
|
||||
if enabled:
|
||||
self._change_option("--sound %s" % hz)
|
||||
else:
|
||||
self._change_option("--sound off")
|
||||
|
||||
def get_ymmixer_types(self):
|
||||
return ("linear", "table", "model")
|
||||
|
||||
def get_ymmixer(self):
|
||||
# values for types are start from 1, not 0
|
||||
return self.get("[Sound]", "YmVolumeMixing")-1
|
||||
|
||||
def set_ymmixer(self, value):
|
||||
self.set("[Sound]", "YmVolumeMixing", value+1)
|
||||
self._change_option("--ym-mixing %s" % self.get_ymmixer_types()[value])
|
||||
|
||||
def get_bufsize(self):
|
||||
return self.get("[Sound]", "nSdlAudioBufferSize")
|
||||
|
||||
def set_bufsize(self, value):
|
||||
value = int(value)
|
||||
if value < 10: value = 10
|
||||
if value > 100: value = 100
|
||||
self.set("[Sound]", "nSdlAudioBufferSize", value)
|
||||
self._change_option("--sound-buffer-size %d" % value)
|
||||
|
||||
def get_sync(self):
|
||||
return self.get("[Sound]", "bEnableSoundSync")
|
||||
|
||||
def set_sync(self, value):
|
||||
self.set("[Sound]", "bEnableSoundSync", value)
|
||||
self._change_option("--sound-sync %s" % str(value))
|
||||
|
||||
def get_mic(self):
|
||||
return self.get("[Sound]", "bEnableMicrophone")
|
||||
|
||||
def set_mic(self, value):
|
||||
self.set("[Sound]", "bEnableMicrophone", value)
|
||||
self._change_option("--mic %s" % str(value))
|
||||
|
||||
# ----------- joystick --------------
|
||||
def get_joystick_types(self):
|
||||
return ("Disabled", "Real joystick", "Keyboard")
|
||||
|
||||
def get_joystick_names(self):
|
||||
return (
|
||||
"ST Joystick 0",
|
||||
"ST Joystick 1",
|
||||
"STE Joypad A",
|
||||
"STE Joypad B",
|
||||
"Parport stick 1",
|
||||
"Parport stick 2"
|
||||
)
|
||||
|
||||
def get_joystick(self, port):
|
||||
# return index to get_joystick_values() array
|
||||
return self.get("[Joystick%d]" % port, "nJoystickMode")
|
||||
|
||||
def set_joystick(self, port, value):
|
||||
# map get_sound_values() index to Hatari config
|
||||
self.set("[Joystick%d]" % port, "nJoystickMode", value)
|
||||
joytype = ("none", "real", "keys")[value]
|
||||
self._change_option("--joy%d %s" % (port, joytype))
|
||||
|
||||
# ------------ floppy handling ---------------
|
||||
def get_floppydir(self):
|
||||
return self.get("[Floppy]", "szDiskImageDirectory")
|
||||
|
||||
def set_floppydir(self, path):
|
||||
return self.set("[Floppy]", "szDiskImageDirectory", path)
|
||||
|
||||
def get_floppy(self, drive):
|
||||
return self.get("[Floppy]", "szDisk%cFileName" % ("A", "B")[drive])
|
||||
|
||||
def set_floppy(self, drive, filename):
|
||||
self.set("[Floppy]", "szDisk%cFileName" % ("A", "B")[drive], filename)
|
||||
self._change_option("--disk-%c" % ("a", "b")[drive], str(filename))
|
||||
|
||||
def get_floppy_drives(self):
|
||||
return (self.get("[Floppy]", "EnableDriveA"), self.get("[Floppy]", "EnableDriveB"))
|
||||
|
||||
def set_floppy_drives(self, drives):
|
||||
idx = 0
|
||||
for drive in ("A", "B"):
|
||||
value = drives[idx]
|
||||
self.set("[Floppy]", "EnableDrive%c" % drive, value)
|
||||
self._change_option("--drive-%c %s" % (drive.lower(), str(value)))
|
||||
idx += 1
|
||||
|
||||
def get_fastfdc(self):
|
||||
return self.get("[Floppy]", "FastFloppy")
|
||||
|
||||
def set_fastfdc(self, value):
|
||||
self.set("[Floppy]", "FastFloppy", value)
|
||||
self._change_option("--fastfdc %s" % str(value))
|
||||
|
||||
def get_doublesided(self):
|
||||
driveA = self.get("[Floppy]", "DriveA_NumberOfHeads")
|
||||
driveB = self.get("[Floppy]", "DriveB_NumberOfHeads")
|
||||
if driveA > 1 or driveB > 1:
|
||||
return True
|
||||
return False
|
||||
|
||||
def set_doublesided(self, value):
|
||||
if value: sides = 2
|
||||
else: sides = 1
|
||||
for drive in ("A", "B"):
|
||||
self.set("[Floppy]", "Drive%c_NumberOfHeads" % drive, sides)
|
||||
self._change_option("--drive-%c-heads %d" % (drive.lower(), sides))
|
||||
|
||||
# ------------- disk protection -------------
|
||||
def get_protection_types(self):
|
||||
return ("Off", "On", "Auto")
|
||||
|
||||
def get_floppy_protection(self):
|
||||
return self.get("[Floppy]", "nWriteProtection")
|
||||
|
||||
def get_hd_protection(self):
|
||||
return self.get("[HardDisk]", "nWriteProtection")
|
||||
|
||||
def set_floppy_protection(self, value):
|
||||
self.set("[Floppy]", "nWriteProtection", value)
|
||||
self._change_option("--protect-floppy %s" % self.get_protection_types()[value])
|
||||
|
||||
def set_hd_protection(self, value):
|
||||
self.set("[HardDisk]", "nWriteProtection", value)
|
||||
self._change_option("--protect-hd %s" % self.get_protection_types()[value])
|
||||
|
||||
# ------------ GEMDOS HD (dir) emulation ---------------
|
||||
def get_hd_cases(self):
|
||||
return ("No conversion", "Upper case", "Lower case")
|
||||
|
||||
def get_hd_case(self):
|
||||
return self.get("[HardDisk]", "nGemdosCase")
|
||||
|
||||
def set_hd_case(self, value):
|
||||
values = ("off", "upper", "lower")
|
||||
self.set("[HardDisk]", "nGemdosCase", value)
|
||||
self._change_option("--gemdos-case %s" % values[value])
|
||||
|
||||
def get_hd_drives(self):
|
||||
return ['skip ACSI/IDE'] + [("%c:" % x) for x in range(ord('C'), ord('Z')+1)]
|
||||
|
||||
def get_hd_drive(self):
|
||||
return self.get("[HardDisk]", "nGemdosDrive") + 1
|
||||
|
||||
def set_hd_drive(self, value):
|
||||
value -= 1
|
||||
self.set("[HardDisk]", "nGemdosDrive", value)
|
||||
drive = chr(ord('C') + value)
|
||||
if value < 0:
|
||||
drive = "skip"
|
||||
self._change_option("--gemdos-drive %s" % drive)
|
||||
|
||||
def get_hd_dir(self):
|
||||
self.get("[HardDisk]", "bUseHardDiskDirectory") # for validation
|
||||
return self.get("[HardDisk]", "szHardDiskDirectory")
|
||||
|
||||
def set_hd_dir(self, dirname):
|
||||
if dirname and os.path.isdir(dirname):
|
||||
self.set("[HardDisk]", "bUseHardDiskDirectory", True)
|
||||
self.set("[HardDisk]", "szHardDiskDirectory", dirname)
|
||||
self._change_option("--harddrive", str(dirname))
|
||||
|
||||
# ------------ ACSI HD (file) ---------------
|
||||
def get_acsi_image(self):
|
||||
self.get("[HardDisk]", "bUseHardDiskImage") # for validation
|
||||
return self.get("[HardDisk]", "szHardDiskImage")
|
||||
|
||||
def set_acsi_image(self, filename):
|
||||
if filename and os.path.isfile(filename):
|
||||
self.set("[HardDisk]", "bUseHardDiskImage", True)
|
||||
self.set("[HardDisk]", "szHardDiskImage", filename)
|
||||
self._change_option("--acsi", str(filename))
|
||||
|
||||
# ------------ IDE master (file) ---------------
|
||||
def get_idemaster_image(self):
|
||||
self.get("[HardDisk]", "bUseIdeMasterHardDiskImage") # for validation
|
||||
return self.get("[HardDisk]", "szIdeMasterHardDiskImage")
|
||||
|
||||
def set_idemaster_image(self, filename):
|
||||
if filename and os.path.isfile(filename):
|
||||
self.set("[HardDisk]", "bUseIdeMasterHardDiskImage", True)
|
||||
self.set("[HardDisk]", "szIdeMasterHardDiskImage", filename)
|
||||
self._change_option("--ide-master", str(filename))
|
||||
|
||||
# ------------ IDE slave (file) ---------------
|
||||
def get_ideslave_image(self):
|
||||
self.get("[HardDisk]", "bUseIdeSlaveHardDiskImage") # for validation
|
||||
return self.get("[HardDisk]", "szIdeSlaveHardDiskImage")
|
||||
|
||||
def set_ideslave_image(self, filename):
|
||||
if filename and os.path.isfile(filename):
|
||||
self.set("[HardDisk]", "bUseIdeSlaveHardDiskImage", True)
|
||||
self.set("[HardDisk]", "szIdeSlaveHardDiskImage", filename)
|
||||
self._change_option("--ide-slave", str(filename))
|
||||
|
||||
# ------------ TOS ROM ---------------
|
||||
def get_tos(self):
|
||||
return self.get("[ROM]", "szTosImageFileName")
|
||||
|
||||
def set_tos(self, filename):
|
||||
self.set("[ROM]", "szTosImageFileName", filename)
|
||||
self._change_option("--tos", str(filename))
|
||||
|
||||
# ------------ memory ---------------
|
||||
def get_memory_names(self):
|
||||
# empty item in list shouldn't be shown, filter them out
|
||||
return ("512kB", "1MB", "2MB", "4MB", "8MB", "14MB")
|
||||
|
||||
def get_memory(self):
|
||||
"return index to what get_memory_names() returns"
|
||||
sizemap = (0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5)
|
||||
memsize = self.get("[Memory]", "nMemorySize")
|
||||
if memsize >= 0 and memsize < len(sizemap):
|
||||
return sizemap[memsize]
|
||||
return 1 # default = 1BM
|
||||
|
||||
def set_memory(self, idx):
|
||||
# map memory item index to memory size
|
||||
sizemap = (0, 1, 2, 4, 8, 14)
|
||||
if idx >= 0 and idx < len(sizemap):
|
||||
memsize = sizemap[idx]
|
||||
else:
|
||||
memsize = 1
|
||||
self.set("[Memory]", "nMemorySize", memsize)
|
||||
self._change_option("--memsize %d" % memsize)
|
||||
|
||||
def get_ttram(self):
|
||||
return self.get("[Memory]", "nTTRamSize")
|
||||
|
||||
def set_ttram(self, memsize):
|
||||
# guarantee correct type (Gtk float -> config int)
|
||||
memsize = int(memsize)
|
||||
self.set("[Memory]", "nTTRamSize", memsize)
|
||||
self._change_option("--ttram %d" % memsize)
|
||||
if memsize:
|
||||
# TT-RAM need 32-bit addressing (i.e. disable 24-bit)
|
||||
self.set("[System]", "bAddressSpace24", False)
|
||||
self._change_option("--addr24 off")
|
||||
else:
|
||||
# switch 24-bit addressing back for compatibility
|
||||
self.set("[System]", "bAddressSpace24", True)
|
||||
self._change_option("--addr24 on", False)
|
||||
|
||||
# ------------ monitor ---------------
|
||||
def get_monitor_types(self):
|
||||
return ("Mono", "RGB", "VGA", "TV")
|
||||
|
||||
def get_monitor(self):
|
||||
return self.get("[Screen]", "nMonitorType")
|
||||
|
||||
def set_monitor(self, value):
|
||||
self.set("[Screen]", "nMonitorType", value)
|
||||
self._change_option("--monitor %s" % ("mono", "rgb", "vga", "tv")[value])
|
||||
|
||||
# ------------ frameskip ---------------
|
||||
def get_frameskip_names(self):
|
||||
return (
|
||||
"Disabled",
|
||||
"1 frame",
|
||||
"2 frames",
|
||||
"3 frames",
|
||||
"4 frames",
|
||||
"Automatic"
|
||||
)
|
||||
|
||||
def get_frameskip(self):
|
||||
fs = self.get("[Screen]", "nFrameSkips")
|
||||
if fs < 0 or fs > 5:
|
||||
return 5
|
||||
return fs
|
||||
|
||||
def set_frameskip(self, value):
|
||||
value = int(value) # guarantee correct type
|
||||
self.set("[Screen]", "nFrameSkips", value)
|
||||
self._change_option("--frameskips %d" % value)
|
||||
|
||||
# ------------ VBL slowdown ---------------
|
||||
def get_slowdown_names(self):
|
||||
return ("Disabled", "2x", "3x", "4x", "5x", "6x", "8x")
|
||||
|
||||
def set_slowdown(self, value):
|
||||
value = 1 + int(value)
|
||||
self._change_option("--slowdown %d" % value)
|
||||
|
||||
# ------------ spec512 ---------------
|
||||
def get_spec512threshold(self):
|
||||
return self.get("[Screen]", "nSpec512Threshold")
|
||||
|
||||
def set_spec512threshold(self, value):
|
||||
value = int(value) # guarantee correct type
|
||||
self.set("[Screen]", "nSpec512Threshold", value)
|
||||
self._change_option("--spec512 %d" % value)
|
||||
|
||||
# --------- keep desktop res -----------
|
||||
def get_desktop(self):
|
||||
return self.get("[Screen]", "bKeepResolution")
|
||||
|
||||
def set_desktop(self, value):
|
||||
self.set("[Screen]", "bKeepResolution", value)
|
||||
self._change_option("--desktop %s" % str(value))
|
||||
|
||||
# --------- keep desktop res - st ------
|
||||
def get_desktop_st(self):
|
||||
return self.get("[Screen]", "bKeepResolutionST")
|
||||
|
||||
def set_desktop_st(self, value):
|
||||
self.set("[Screen]", "bKeepResolutionST", value)
|
||||
self._change_option("--desktop-st %s" % str(value))
|
||||
|
||||
# ------------ force max ---------------
|
||||
def get_force_max(self):
|
||||
return self.get("[Screen]", "bForceMax")
|
||||
|
||||
def set_force_max(self, value):
|
||||
self.set("[Screen]", "bForceMax", value)
|
||||
self._change_option("--force-max %s" % str(value))
|
||||
|
||||
# ------------ show borders ---------------
|
||||
def get_borders(self):
|
||||
return self.get("[Screen]", "bAllowOverscan")
|
||||
|
||||
def set_borders(self, value):
|
||||
self.set("[Screen]", "bAllowOverscan", value)
|
||||
self._change_option("--borders %s" % str(value))
|
||||
|
||||
# ------------ show statusbar ---------------
|
||||
def get_statusbar(self):
|
||||
return self.get("[Screen]", "bShowStatusbar")
|
||||
|
||||
def set_statusbar(self, value):
|
||||
self.set("[Screen]", "bShowStatusbar", value)
|
||||
self._change_option("--statusbar %s" % str(value))
|
||||
|
||||
# ------------ crop statusbar ---------------
|
||||
def get_crop(self):
|
||||
return self.get("[Screen]", "bCrop")
|
||||
|
||||
def set_crop(self, value):
|
||||
self.set("[Screen]", "bCrop", value)
|
||||
self._change_option("--crop %s" % str(value))
|
||||
|
||||
# ------------ show led ---------------
|
||||
def get_led(self):
|
||||
return self.get("[Screen]", "bShowDriveLed")
|
||||
|
||||
def set_led(self, value):
|
||||
self.set("[Screen]", "bShowDriveLed", value)
|
||||
self._change_option("--drive-led %s" % str(value))
|
||||
|
||||
# ------------ monitor aspect ratio ---------------
|
||||
def get_aspectcorrection(self):
|
||||
return self.get("[Screen]", "bAspectCorrect")
|
||||
|
||||
def set_aspectcorrection(self, value):
|
||||
self.set("[Screen]", "bAspectCorrect", value)
|
||||
self._change_option("--aspect %s" % str(value))
|
||||
|
||||
# ------------ max window size ---------------
|
||||
def set_desktop_size(self, w, h):
|
||||
self._desktop_w = w
|
||||
self._desktop_h = h
|
||||
|
||||
def get_desktop_size(self):
|
||||
return (self._desktop_w, self._desktop_h)
|
||||
|
||||
def get_max_size(self):
|
||||
w = self.get("[Screen]", "nMaxWidth")
|
||||
h = self.get("[Screen]", "nMaxHeight")
|
||||
# default to desktop size?
|
||||
if not (w or h):
|
||||
w = self._desktop_w
|
||||
h = self._desktop_h
|
||||
return (w, h)
|
||||
|
||||
def set_max_size(self, w, h):
|
||||
# guarantee correct type (Gtk float -> config int)
|
||||
w = int(w); h = int(h)
|
||||
self.set("[Screen]", "nMaxWidth", w)
|
||||
self.set("[Screen]", "nMaxHeight", h)
|
||||
self._change_option("--max-width %d" % w)
|
||||
self._change_option("--max-height %d" % h)
|
||||
|
||||
# TODO: remove once UI doesn't need this anymore
|
||||
def set_zoom(self, value):
|
||||
print("Just setting Zoom, configuration doesn't anymore have setting for this.")
|
||||
if value:
|
||||
zoom = 2
|
||||
else:
|
||||
zoom = 1
|
||||
self._change_option("--zoom %d" % zoom)
|
||||
|
||||
# ------------ configured Hatari window size ---------------
|
||||
def get_window_size(self):
|
||||
if self.get("[Screen]", "bFullScreen"):
|
||||
print("WARNING: don't start Hatari UI with fullscreened Hatari!")
|
||||
|
||||
# VDI resolution?
|
||||
if self.get("[Screen]", "bUseExtVdiResolutions"):
|
||||
width = self.get("[Screen]", "nVdiWidth")
|
||||
height = self.get("[Screen]", "nVdiHeight")
|
||||
return (width, height)
|
||||
|
||||
# window sizes for other than ST & STE can differ
|
||||
if self.get("[System]", "nMachineType") not in (0, 1):
|
||||
print("WARNING: neither ST nor STE machine, window size inaccurate!")
|
||||
videl = True
|
||||
else:
|
||||
videl = False
|
||||
|
||||
# mono monitor?
|
||||
if self.get_monitor() == 0:
|
||||
return (640, 400)
|
||||
|
||||
# no, color
|
||||
width = 320
|
||||
height = 200
|
||||
# statusbar?
|
||||
if self.get_statusbar():
|
||||
sbar = 12
|
||||
height += sbar
|
||||
else:
|
||||
sbar = 0
|
||||
# zoom?
|
||||
maxw, maxh = self.get_max_size()
|
||||
if 2*width <= maxw and 2*height <= maxh:
|
||||
width *= 2
|
||||
height *= 2
|
||||
zoom = 2
|
||||
else:
|
||||
zoom = 1
|
||||
# overscan borders?
|
||||
if self.get_borders() and not videl:
|
||||
# properly aligned borders on top of zooming
|
||||
leftx = (maxw-width)/zoom
|
||||
borderx = 2*(min(48,leftx/2)/16)*16
|
||||
lefty = (maxh-height)/zoom
|
||||
bordery = min(29+47, lefty)
|
||||
width += zoom*borderx
|
||||
height += zoom*bordery
|
||||
|
||||
return (width, height)
|
42
python-ui/hatariui
Executable file
@ -0,0 +1,42 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# Don't modify the 'path' or 'conf' variable names or initial values,
|
||||
# those will be replaced by Makefile when this script is installed.
|
||||
|
||||
path=${0%/*}
|
||||
name=${0##*/}
|
||||
|
||||
if [ ! -e $path/$name.py ]; then
|
||||
# Assume package has been relocated, try relative data directory:
|
||||
path=${0%/*}/../share/hatari/hatariui
|
||||
fi
|
||||
|
||||
# Assume hatari system configuration file dir is relative to hatariui dir
|
||||
# (usually system config file isn't installed, but if defaults need to be
|
||||
# configured differently from Hatari source code defaults, they're better
|
||||
# done with system config file than patching sources).
|
||||
conf=${path%/*}/../etc
|
||||
# checked by hatari UI
|
||||
export HATARI_SYSTEM_CONFDIR=$conf
|
||||
|
||||
# example setup for Hatari UI
|
||||
$path/$name.py --right "about,|,run,pause,forward,|,reset,|,quit" --embed $*
|
||||
exit 0
|
||||
|
||||
# test setup without embedding, duplicate toggles
|
||||
$path/$name.py --top "about,run,pause,quit" \
|
||||
--panel "Testpanel,pause,>,close" \
|
||||
--bottom "sound,|,forward,pause,|,Testpanel" \
|
||||
$*
|
||||
exit 0
|
||||
|
||||
# test setup with embedding and all available controls
|
||||
$path/$name.py --embed \
|
||||
--top "about,|,run,pause,|,reset,debug,|,quit" \
|
||||
--left "run,pause,reset,machine,about" \
|
||||
--panel "Keys,F1=59,F2=60,F3=61,F4=62,F5=63,F6=64,F7=65,F8=66,F9=67,F10=68,>,Macro=Test,Undo=97,Help=98,Enter=114,>,close" \
|
||||
--panel "Misc,|,forward,full,|,sound,>,shot,>,close" \
|
||||
--bottom "forward,full,Misc,Keys,input,display,debug,trace" \
|
||||
--right "forward,full,Misc,Keys,input,display,Help=98" \
|
||||
$*
|
||||
exit 0
|
227
python-ui/hatariui.1
Normal file
@ -0,0 +1,227 @@
|
||||
.\" Hey, EMACS: -*- nroff -*-
|
||||
.\" First parameter, NAME, should be all caps
|
||||
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
||||
.\" other parameters are allowed: see man(7), man(1)
|
||||
.TH "hatariui" "1" "2010-05-30" "Hatari" "Hatari UI"
|
||||
.SH "NAME"
|
||||
hatariui \- Python/Gtk UI for Hatari
|
||||
.SH "SYNOPSIS"
|
||||
.B hatariui | hatariui.py
|
||||
.RI [options]
|
||||
.RI [directory|diskimage|program]
|
||||
.SH "DESCRIPTION"
|
||||
.I hatariui
|
||||
is a Python/Gtk UI for Hatari which can either embed the Hatari window
|
||||
(on X11 systems) or run in a separate window. By default it provides
|
||||
a normal application menu and some extra button for faster access to
|
||||
fast\-forward etc. functionality, but these are fully configurable
|
||||
with the command line options. While it lacks support for some of
|
||||
the Hatari configuration options that Hatari's SDL GUI has, it also
|
||||
supports some options that the Hatari's built\-in SDL UI doesn't.
|
||||
.PP
|
||||
Besides the UI configurability, some of the other advantages hatariui has
|
||||
over the SDL interface included with Hatari itself are use of a normal
|
||||
Gtk file selector with all of its features (directory shortcuts etc),
|
||||
support for UTF\-8 (in file names) and in general blending better to
|
||||
the user's desktop environment.
|
||||
.PP
|
||||
Additionally, Hatari can run while one uses UI configuration dialogs,
|
||||
and it can stop Hatari completely to better save the battery on mobile
|
||||
computers. For devices without a keyboard, it offers a a text input
|
||||
dialog and one can configure (from command line) buttons for often used
|
||||
strings.
|
||||
.SH "HATARIUI / HATARIUI.PY"
|
||||
.I hatariui
|
||||
is actually a shell script wrapper for the hatariui.py Python script.
|
||||
It's used to run the Python script with suitable options for default
|
||||
usage and to set up the correct installation directory for the rest
|
||||
of the Hatari UI Python scripts and data files.
|
||||
.PP
|
||||
Options below are actually for hatariui.py script. If you want to
|
||||
change options given for it, modify the hatariui shell script or
|
||||
make your own based on the installed one.
|
||||
.\" following command line helps in updating the options:
|
||||
.\" hatariui.py --help|sed -e 's/^\t\+/.TP\n.B /' -e 's/\t\+/\n/g' -e 's/-/\\-/g' >> hatariui.1
|
||||
.SH "OPTIONS"
|
||||
.TP
|
||||
.B \-h, \-\-help
|
||||
Hatari UI command line help
|
||||
.TP
|
||||
.B \-n, \-\-nomenu
|
||||
Omit menubar from the window
|
||||
.TP
|
||||
.B \-e, \-\-embed
|
||||
Embed Hatari window (to middle of controls)
|
||||
.TP
|
||||
.B \-f, \-\-fullscreen
|
||||
Start in fullscreen
|
||||
.TP
|
||||
.B \-l, \-\-left <controls>
|
||||
Add a toolbar at left
|
||||
.TP
|
||||
.B \-r, \-\-right <controls>
|
||||
Add a toolbar at right
|
||||
.TP
|
||||
.B \-t, \-\-top <controls>
|
||||
Add a toolbar at top
|
||||
.TP
|
||||
.B \-b, \-\-bottom <controls>
|
||||
Add a toolbar at bottom
|
||||
.TP
|
||||
.B \-p, \-\-panel <name>,<controls>
|
||||
Add a separate window with given name and controls
|
||||
.PP
|
||||
You can have only one toolbar on each side of the Hatari window.
|
||||
Panels are separate windows and you can has as many of them as you wish.
|
||||
For each panel you need to add a control with the name of the panel
|
||||
(see "MyPanel" in examples).
|
||||
.PP
|
||||
Following controls can are available for toolbars and panels:
|
||||
.TP
|
||||
.B |
|
||||
Separator between controls
|
||||
.TP
|
||||
.B >
|
||||
Start next toolbar row in panel windows
|
||||
.TP
|
||||
.B compatibility
|
||||
Hatari compatibility list
|
||||
.TP
|
||||
.B harddisk
|
||||
Hard disk images and directories
|
||||
.TP
|
||||
.B reset
|
||||
Warm or cold reset Hatari
|
||||
.TP
|
||||
.B sconfig
|
||||
Save configuration
|
||||
.TP
|
||||
.B bugs
|
||||
Report a bug
|
||||
.TP
|
||||
.B display
|
||||
Display settings
|
||||
.TP
|
||||
.B authors
|
||||
Hatari authors
|
||||
.TP
|
||||
.B forward
|
||||
Whether to fast forward Hatari (needs fast machine)
|
||||
.TP
|
||||
.B debug
|
||||
Activate Hatari debugger
|
||||
.TP
|
||||
.B quit
|
||||
Quit Hatari UI
|
||||
.TP
|
||||
.B hatari
|
||||
Hatari home page
|
||||
.TP
|
||||
.B recanim
|
||||
Record animation
|
||||
.TP
|
||||
.B recsound
|
||||
Record YM/Wav
|
||||
.TP
|
||||
.B mails
|
||||
Hatari mailing lists
|
||||
.TP
|
||||
.B floppy
|
||||
Floppy images
|
||||
.TP
|
||||
.B device
|
||||
Toggle Midi, Printer, RS232 peripherals
|
||||
.TP
|
||||
.B load
|
||||
Load emulation snapshot
|
||||
.TP
|
||||
.B lconfig
|
||||
Load configuration
|
||||
.TP
|
||||
.B path
|
||||
Device & save file paths
|
||||
.TP
|
||||
.B machine
|
||||
Hatari st/e/tt/falcon configuration
|
||||
.TP
|
||||
.B todo
|
||||
Hatari TODO
|
||||
.TP
|
||||
.B hatariui
|
||||
Hatari UI home page
|
||||
.TP
|
||||
.B save
|
||||
Save emulation snapshot
|
||||
.TP
|
||||
.B joystick
|
||||
Joystick settings
|
||||
.TP
|
||||
.B trace
|
||||
Hatari tracing setup
|
||||
.TP
|
||||
.B pause
|
||||
Pause Hatari to save battery
|
||||
.TP
|
||||
.B about
|
||||
Hatari UI information
|
||||
.TP
|
||||
.B release
|
||||
Hatari release notes
|
||||
.TP
|
||||
.B full
|
||||
Toggle whether Hatari is fullscreen
|
||||
.TP
|
||||
.B manual
|
||||
Hatari manual
|
||||
.TP
|
||||
.B input
|
||||
Simulate text input and mouse clicks
|
||||
.TP
|
||||
.B sound
|
||||
Sound settings
|
||||
.TP
|
||||
.B changes
|
||||
Latest Hatari changes
|
||||
.TP
|
||||
.B run
|
||||
(Re\-)run Hatari
|
||||
.TP
|
||||
.B shot
|
||||
Grab a screenshot
|
||||
.TP
|
||||
.B <panel name>
|
||||
Button for the specified panel window
|
||||
.TP
|
||||
.B <name>=<string/code>
|
||||
Synthetize string or single key <code>
|
||||
.PP
|
||||
If no options are given, the UI uses basic controls.
|
||||
.SH "EXAMPLES"
|
||||
Example on how to add top, right and bottom toolbars and a separate
|
||||
"MyPanel" panel window:
|
||||
.nf
|
||||
hatariui.py \-\-embed \\
|
||||
\-t "about,run,pause,quit" \\
|
||||
\-p "MyPanel,Macro=Test,Undo=97,Help=98,>,F1=59,F2=60,>,close" \\
|
||||
\-r "paste,debug,trace,machine,MyPanel" \\
|
||||
\-b "sound,|,forward,|,fullscreen"
|
||||
.fi
|
||||
.PP
|
||||
For more examples on Hatari UI options usage, see the hatariui shell
|
||||
script.
|
||||
.SH "SEE ALSO"
|
||||
.IR hmsa (1),
|
||||
.IR hatariui (1),
|
||||
.IR hconsole (1)
|
||||
.SH "COPYRIGHT"
|
||||
Hatari UI is written by Eero Tamminen <oak at helsinkinet fi>.
|
||||
.PP
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or (at
|
||||
your option) any later version.
|
||||
.PP
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
7
python-ui/hatariui.desktop
Normal file
@ -0,0 +1,7 @@
|
||||
[Desktop Entry]
|
||||
Encoding=UTF-8
|
||||
Version=1.0
|
||||
Type=Application
|
||||
Name=Hatari UI
|
||||
Exec=hatariui
|
||||
Icon=hatari
|
763
python-ui/hatariui.py
Executable file
@ -0,0 +1,763 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A PyGtk UI for Hatari that can embed the Hatari emulator window.
|
||||
#
|
||||
# Requires PyGtk (python-gtk2) package and its dependencies to be present.
|
||||
#
|
||||
# Copyright (C) 2008-2011 by Eero Tamminen
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
import os
|
||||
import sys
|
||||
import getopt
|
||||
|
||||
# use correct version of pygtk/gtk
|
||||
import pygtk
|
||||
pygtk.require('2.0')
|
||||
import gtk
|
||||
import gobject
|
||||
|
||||
from debugui import HatariDebugUI
|
||||
from hatari import Hatari, HatariConfigMapping
|
||||
from uihelpers import UInfo, UIHelp, create_button, create_toolbutton, \
|
||||
create_toggle, HatariTextInsert, get_open_filename, get_save_filename
|
||||
from dialogs import AboutDialog, TodoDialog, NoteDialog, ErrorDialog, \
|
||||
InputDialog, KillDialog, QuitSaveDialog, ResetDialog, TraceDialog, \
|
||||
FloppyDialog, HardDiskDialog, DisplayDialog, JoystickDialog, \
|
||||
MachineDialog, PeripheralDialog, PathDialog, SoundDialog
|
||||
|
||||
|
||||
# helper functions to match callback args
|
||||
def window_hide_cb(window, arg):
|
||||
window.hide()
|
||||
return True
|
||||
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
# Class with Hatari and configuration instances which methods are
|
||||
# called to change those (with additional dialogs or directly).
|
||||
# Owns the application window and socket widget embedding Hatari.
|
||||
class UICallbacks:
|
||||
tmpconfpath = os.path.expanduser("~/.hatari/.tmp.cfg")
|
||||
def __init__(self):
|
||||
# Hatari and configuration
|
||||
self.hatari = Hatari()
|
||||
error = self.hatari.is_compatible()
|
||||
if error:
|
||||
ErrorDialog(None).run(error)
|
||||
sys.exit(-1)
|
||||
|
||||
self.config = HatariConfigMapping(self.hatari)
|
||||
try:
|
||||
self.config.validate()
|
||||
except (KeyError, AttributeError):
|
||||
NoteDialog(None).run("Loading Hatari configuration failed!\nRetrying after saving Hatari configuration.")
|
||||
self.hatari.save_config()
|
||||
self.config = HatariConfigMapping(self.hatari)
|
||||
self.config.validate()
|
||||
|
||||
# windows are created when needed
|
||||
self.mainwin = None
|
||||
self.hatariwin = None
|
||||
self.debugui = None
|
||||
self.panels = {}
|
||||
|
||||
# dialogs are created when needed
|
||||
self.aboutdialog = None
|
||||
self.inputdialog = None
|
||||
self.tracedialog = None
|
||||
self.resetdialog = None
|
||||
self.quitdialog = None
|
||||
self.killdialog = None
|
||||
|
||||
self.floppydialog = None
|
||||
self.harddiskdialog = None
|
||||
self.displaydialog = None
|
||||
self.joystickdialog = None
|
||||
self.machinedialog = None
|
||||
self.peripheraldialog = None
|
||||
self.sounddialog = None
|
||||
self.pathdialog = None
|
||||
|
||||
# used by run()
|
||||
self.memstate = None
|
||||
self.floppy = None
|
||||
self.io_id = None
|
||||
|
||||
# TODO: Hatari UI own configuration settings save/load
|
||||
self.tracepoints = None
|
||||
|
||||
def _reset_config_dialogs(self):
|
||||
self.floppydialog = None
|
||||
self.harddiskdialog = None
|
||||
self.displaydialog = None
|
||||
self.joystickdialog = None
|
||||
self.machinedialog = None
|
||||
self.peripheraldialog = None
|
||||
self.sounddialog = None
|
||||
self.pathdialog = None
|
||||
|
||||
# ---------- create UI ----------------
|
||||
def create_ui(self, accelgroup, menu, toolbars, fullscreen, embed):
|
||||
"create_ui(menu, toolbars, fullscreen, embed)"
|
||||
# add horizontal elements
|
||||
hbox = gtk.HBox()
|
||||
if toolbars["left"]:
|
||||
hbox.pack_start(toolbars["left"], False, True)
|
||||
if embed:
|
||||
self._add_uisocket(hbox)
|
||||
if toolbars["right"]:
|
||||
hbox.pack_start(toolbars["right"], False, True)
|
||||
# add vertical elements
|
||||
vbox = gtk.VBox()
|
||||
if menu:
|
||||
vbox.add(menu)
|
||||
if toolbars["top"]:
|
||||
vbox.pack_start(toolbars["top"], False, True)
|
||||
vbox.add(hbox)
|
||||
if toolbars["bottom"]:
|
||||
vbox.pack_start(toolbars["bottom"], False, True)
|
||||
# put them to main window
|
||||
mainwin = gtk.Window(gtk.WINDOW_TOPLEVEL)
|
||||
mainwin.set_title("%s %s" % (UInfo.name, UInfo.version))
|
||||
mainwin.set_icon_from_file(UInfo.icon)
|
||||
if accelgroup:
|
||||
mainwin.add_accel_group(accelgroup)
|
||||
if fullscreen:
|
||||
mainwin.fullscreen()
|
||||
mainwin.add(vbox)
|
||||
mainwin.show_all()
|
||||
# for run and quit callbacks
|
||||
self.killdialog = KillDialog(mainwin)
|
||||
mainwin.connect("delete_event", self.quit)
|
||||
self.mainwin = mainwin
|
||||
|
||||
def _add_uisocket(self, box):
|
||||
# add Hatari parent container to given box
|
||||
socket = gtk.Socket()
|
||||
# without this, closing Hatari would remove the socket widget
|
||||
socket.connect("plug-removed", lambda obj: True)
|
||||
socket.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("black"))
|
||||
socket.set_events(gtk.gdk.ALL_EVENTS_MASK)
|
||||
socket.set_flags(gtk.CAN_FOCUS)
|
||||
# set max Hatari window size = desktop size
|
||||
self.config.set_desktop_size(gtk.gdk.screen_width(), gtk.gdk.screen_height())
|
||||
# set initial embedded hatari size
|
||||
width, height = self.config.get_window_size()
|
||||
socket.set_size_request(width, height)
|
||||
# no resizing for the Hatari window
|
||||
box.pack_start(socket, False, False)
|
||||
self.hatariwin = socket
|
||||
|
||||
# ------- run callback -----------
|
||||
def _socket_cb(self, fd, event):
|
||||
if event != gobject.IO_IN:
|
||||
# hatari process died, make sure Hatari instance notices
|
||||
self.hatari.kill()
|
||||
return False
|
||||
width, height = self.hatari.get_embed_info()
|
||||
print("New size = %d x %d" % (width, height))
|
||||
oldwidth, oldheight = self.hatariwin.get_size_request()
|
||||
self.hatariwin.set_size_request(width, height)
|
||||
if width < oldwidth or height < oldheight:
|
||||
# force also mainwin smaller (it automatically grows)
|
||||
self.mainwin.resize(width, height)
|
||||
return True
|
||||
|
||||
def run(self, widget = None):
|
||||
if not self.killdialog.run(self.hatari):
|
||||
return
|
||||
if self.io_id:
|
||||
gobject.source_remove(self.io_id)
|
||||
args = ["--configfile"]
|
||||
# whether to use Hatari config or unsaved Hatari UI config?
|
||||
if self.config.is_changed():
|
||||
args += [self.config.save_tmp(self.tmpconfpath)]
|
||||
else:
|
||||
args += [self.config.get_path()]
|
||||
if self.memstate:
|
||||
args += self.memstate
|
||||
# only way to change boot order is to specify disk on command line
|
||||
if self.floppy:
|
||||
args += self.floppy
|
||||
if self.hatariwin:
|
||||
size = self.hatariwin.window.get_size()
|
||||
self.hatari.run(args, self.hatariwin.window)
|
||||
# get notifications of Hatari window size changes
|
||||
self.hatari.enable_embed_info()
|
||||
socket = self.hatari.get_control_socket().fileno()
|
||||
events = gobject.IO_IN | gobject.IO_HUP | gobject.IO_ERR
|
||||
self.io_id = gobject.io_add_watch(socket, events, self._socket_cb)
|
||||
# all keyboard events should go to Hatari window
|
||||
self.hatariwin.grab_focus()
|
||||
else:
|
||||
self.hatari.run(args)
|
||||
|
||||
def set_floppy(self, floppy):
|
||||
self.floppy = floppy
|
||||
|
||||
# ------- quit callback -----------
|
||||
def quit(self, widget, arg = None):
|
||||
# due to Gtk API, needs to return True when *not* quitting
|
||||
if not self.killdialog.run(self.hatari):
|
||||
return True
|
||||
if self.io_id:
|
||||
gobject.source_remove(self.io_id)
|
||||
if self.config.is_changed():
|
||||
if not self.quitdialog:
|
||||
self.quitdialog = QuitSaveDialog(self.mainwin)
|
||||
if not self.quitdialog.run(self.config):
|
||||
return True
|
||||
gtk.main_quit()
|
||||
if os.path.exists(self.tmpconfpath):
|
||||
os.unlink(self.tmpconfpath)
|
||||
# continue to mainwin destroy if called by delete_event
|
||||
return False
|
||||
|
||||
# ------- pause callback -----------
|
||||
def pause(self, widget):
|
||||
if widget.get_active():
|
||||
self.hatari.pause()
|
||||
else:
|
||||
self.hatari.unpause()
|
||||
|
||||
# dialogs
|
||||
# ------- reset callback -----------
|
||||
def reset(self, widget):
|
||||
if not self.resetdialog:
|
||||
self.resetdialog = ResetDialog(self.mainwin)
|
||||
self.resetdialog.run(self.hatari)
|
||||
|
||||
# ------- about callback -----------
|
||||
def about(self, widget):
|
||||
if not self.aboutdialog:
|
||||
self.aboutdialog = AboutDialog(self.mainwin)
|
||||
self.aboutdialog.run()
|
||||
|
||||
# ------- input callback -----------
|
||||
def inputs(self, widget):
|
||||
if not self.inputdialog:
|
||||
self.inputdialog = InputDialog(self.mainwin)
|
||||
self.inputdialog.run(self.hatari)
|
||||
|
||||
# ------- floppydisk callback -----------
|
||||
def floppydisk(self, widget):
|
||||
if not self.floppydialog:
|
||||
self.floppydialog = FloppyDialog(self.mainwin)
|
||||
self.floppydialog.run(self.config)
|
||||
|
||||
# ------- harddisk callback -----------
|
||||
def harddisk(self, widget):
|
||||
if not self.harddiskdialog:
|
||||
self.harddiskdialog = HardDiskDialog(self.mainwin)
|
||||
self.harddiskdialog.run(self.config)
|
||||
|
||||
# ------- display callback -----------
|
||||
def display(self, widget):
|
||||
if not self.displaydialog:
|
||||
self.displaydialog = DisplayDialog(self.mainwin)
|
||||
self.displaydialog.run(self.config)
|
||||
|
||||
# ------- joystick callback -----------
|
||||
def joystick(self, widget):
|
||||
if not self.joystickdialog:
|
||||
self.joystickdialog = JoystickDialog(self.mainwin)
|
||||
self.joystickdialog.run(self.config)
|
||||
|
||||
# ------- machine callback -----------
|
||||
def machine(self, widget):
|
||||
if not self.machinedialog:
|
||||
self.machinedialog = MachineDialog(self.mainwin)
|
||||
if self.machinedialog.run(self.config):
|
||||
self.hatari.trigger_shortcut("coldreset")
|
||||
|
||||
# ------- peripheral callback -----------
|
||||
def peripheral(self, widget):
|
||||
if not self.peripheraldialog:
|
||||
self.peripheraldialog = PeripheralDialog(self.mainwin)
|
||||
self.peripheraldialog.run(self.config)
|
||||
|
||||
# ------- sound callback -----------
|
||||
def sound(self, widget):
|
||||
if not self.sounddialog:
|
||||
self.sounddialog = SoundDialog(self.mainwin)
|
||||
self.sounddialog.run(self.config)
|
||||
|
||||
# ------- path callback -----------
|
||||
def path(self, widget):
|
||||
if not self.pathdialog:
|
||||
self.pathdialog = PathDialog(self.mainwin)
|
||||
self.pathdialog.run(self.config)
|
||||
|
||||
# ------- debug callback -----------
|
||||
def debugger(self, widget):
|
||||
if not self.debugui:
|
||||
self.debugui = HatariDebugUI(self.hatari)
|
||||
self.debugui.show()
|
||||
|
||||
# ------- trace callback -----------
|
||||
def trace(self, widget):
|
||||
if not self.tracedialog:
|
||||
self.tracedialog = TraceDialog(self.mainwin)
|
||||
self.tracepoints = self.tracedialog.run(self.hatari, self.tracepoints)
|
||||
|
||||
# ------ snapshot load/save callbacks ---------
|
||||
def load(self, widget):
|
||||
path = os.path.expanduser("~/.hatari/hatari.sav")
|
||||
filename = get_open_filename("Select snapshot", self.mainwin, path)
|
||||
if filename:
|
||||
self.memstate = ["--memstate", filename]
|
||||
self.run()
|
||||
return True
|
||||
return False
|
||||
|
||||
def save(self, widget):
|
||||
self.hatari.trigger_shortcut("savemem")
|
||||
|
||||
# ------ config load/save callbacks ---------
|
||||
def config_load(self, widget):
|
||||
path = self.config.get_path()
|
||||
filename = get_open_filename("Select configuration file", self.mainwin, path)
|
||||
if filename:
|
||||
self.hatari.change_option("--configfile %s" % filename)
|
||||
self.config.load(filename)
|
||||
self._reset_config_dialogs()
|
||||
return True
|
||||
return False
|
||||
|
||||
def config_save(self, widget):
|
||||
path = self.config.get_path()
|
||||
filename = get_save_filename("Save configuration as...", self.mainwin, path)
|
||||
if filename:
|
||||
self.config.save_as(filename)
|
||||
return True
|
||||
return False
|
||||
|
||||
# ------- fast forward callback -----------
|
||||
def set_fastforward(self, widget):
|
||||
self.config.set_fastforward(widget.get_active())
|
||||
|
||||
def get_fastforward(self):
|
||||
return self.config.get_fastforward()
|
||||
|
||||
# ------- fullscreen callback -----------
|
||||
def set_fullscreen(self, widget):
|
||||
# if user can select this, Hatari isn't in fullscreen
|
||||
self.hatari.change_option("--fullscreen")
|
||||
|
||||
# ------- screenshot callback -----------
|
||||
def screenshot(self, widget):
|
||||
self.hatari.trigger_shortcut("screenshot")
|
||||
|
||||
# ------- record callbacks -----------
|
||||
def recanim(self, widget):
|
||||
self.hatari.trigger_shortcut("recanim")
|
||||
|
||||
def recsound(self, widget):
|
||||
self.hatari.trigger_shortcut("recsound")
|
||||
|
||||
# ------- insert key special callback -----------
|
||||
def keypress(self, widget, code):
|
||||
self.hatari.insert_event("keypress %s" % code)
|
||||
|
||||
def textinsert(self, widget, text):
|
||||
HatariTextInsert(self.hatari, text)
|
||||
|
||||
# ------- panel callback -----------
|
||||
def panel(self, action, box):
|
||||
title = action.get_name()
|
||||
if title not in self.panels:
|
||||
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
|
||||
window.set_transient_for(self.mainwin)
|
||||
window.set_icon_from_file(UInfo.icon)
|
||||
window.set_title(title)
|
||||
window.add(box)
|
||||
window.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
|
||||
window.connect("delete_event", window_hide_cb)
|
||||
self.panels[title] = window
|
||||
else:
|
||||
window = self.panels[title]
|
||||
window.show_all()
|
||||
window.deiconify()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
# class for creating menus, toolbars and panels
|
||||
# and managing actions bound to them
|
||||
class UIActions:
|
||||
def __init__(self):
|
||||
cb = self.callbacks = UICallbacks()
|
||||
|
||||
self.help = UIHelp()
|
||||
|
||||
self.actions = gtk.ActionGroup("All")
|
||||
|
||||
# name, icon ID, label, accel, tooltip, callback
|
||||
self.actions.add_toggle_actions((
|
||||
# TODO: how to know when these are changed from inside Hatari?
|
||||
("recanim", gtk.STOCK_MEDIA_RECORD, "Record animation", "<Ctrl>A", "Record animation", cb.recanim),
|
||||
("recsound", gtk.STOCK_MEDIA_RECORD, "Record sound", "<Ctrl>W", "Record YM/Wav", cb.recsound),
|
||||
("pause", gtk.STOCK_MEDIA_PAUSE, "Pause", "<Ctrl>P", "Pause Hatari to save battery", cb.pause),
|
||||
("forward", gtk.STOCK_MEDIA_FORWARD, "Forward", "<Ctrl>F", "Whether to fast forward Hatari (needs fast machine)", cb.set_fastforward, cb.get_fastforward())
|
||||
))
|
||||
|
||||
# name, icon ID, label, accel, tooltip, callback
|
||||
self.actions.add_actions((
|
||||
("load", gtk.STOCK_OPEN, "Load snapshot...", "<Ctrl>L", "Load emulation snapshot", cb.load),
|
||||
("save", gtk.STOCK_SAVE, "Save snapshot", "<Ctrl>S", "Save emulation snapshot", cb.save),
|
||||
("shot", gtk.STOCK_MEDIA_RECORD, "Grab screenshot", "<Ctrl>G", "Grab a screenshot", cb.screenshot),
|
||||
("quit", gtk.STOCK_QUIT, "Quit", "<Ctrl>Q", "Quit Hatari UI", cb.quit),
|
||||
|
||||
("run", gtk.STOCK_MEDIA_PLAY, "Run", "<Ctrl>R", "(Re-)run Hatari", cb.run),
|
||||
("full", gtk.STOCK_FULLSCREEN, "Fullscreen", "<Ctrl>U", "Toggle whether Hatari is fullscreen", cb.set_fullscreen),
|
||||
("input", gtk.STOCK_SPELL_CHECK, "Inputs...", "<Ctrl>N", "Simulate text input and mouse clicks", cb.inputs),
|
||||
("reset", gtk.STOCK_REFRESH, "Reset...", "<Ctrl>E", "Warm or cold reset Hatari", cb.reset),
|
||||
|
||||
("display", gtk.STOCK_PREFERENCES, "Display...", "<Ctrl>Y", "Display settings", cb.display),
|
||||
("floppy", gtk.STOCK_FLOPPY, "Floppies...", "<Ctrl>D", "Floppy images", cb.floppydisk),
|
||||
("harddisk", gtk.STOCK_HARDDISK, "Hard disks...", "<Ctrl>H", "Hard disk images and directories", cb.harddisk),
|
||||
("joystick", gtk.STOCK_CONNECT, "Joysticks...", "<Ctrl>J", "Joystick settings", cb.joystick),
|
||||
("machine", gtk.STOCK_HARDDISK, "Machine...", "<Ctrl>M", "Hatari st/e/tt/falcon configuration", cb.machine),
|
||||
("device", gtk.STOCK_PRINT, "Peripherals...", "<Ctrl>V", "Toggle Midi, Printer, RS232 peripherals", cb.peripheral),
|
||||
("sound", gtk.STOCK_PROPERTIES, "Sound...", "<Ctrl>O", "Sound settings", cb.sound),
|
||||
|
||||
("path", gtk.STOCK_DIRECTORY, "Paths...", None, "Device & save file paths", cb.path),
|
||||
("lconfig", gtk.STOCK_OPEN, "Load config...", "<Ctrl>C", "Load configuration", self.config_load),
|
||||
("sconfig", gtk.STOCK_SAVE_AS, "Save config as...", None, "Save configuration", cb.config_save),
|
||||
|
||||
("debug", gtk.STOCK_FIND, "Debugger...", "<Ctrl>B", "Activate Hatari debugger", cb.debugger),
|
||||
("trace", gtk.STOCK_EXECUTE, "Trace settings...", "<Ctrl>T", "Hatari tracing setup", cb.trace),
|
||||
|
||||
("manual", None, "Hatari manual", None, None, self.help.view_hatari_manual),
|
||||
("compatibility", None, "Hatari compatibility list", None, None, self.help.view_hatari_compatibility),
|
||||
("release", None, "Hatari release notes", None, None, self.help.view_hatari_releasenotes),
|
||||
("todo", None, "Hatari TODO", None, None, self.help.view_hatari_todo),
|
||||
("mails", None, "Hatari mailing lists", None, None, self.help.view_hatari_mails),
|
||||
("changes", None, "Latest Hatari changes", None, None, self.help.view_hatari_repository),
|
||||
("authors", None, "Hatari authors", None, None, self.help.view_hatari_authors),
|
||||
("hatari", None, "Hatari home page", None, None, self.help.view_hatari_page),
|
||||
("hatariui", None, "Hatari UI home page", None, None, self.help.view_hatariui_page),
|
||||
("about", gtk.STOCK_INFO, "Hatari UI info", "<Ctrl>I", "Hatari UI information", cb.about)
|
||||
))
|
||||
self.action_names = [x.get_name() for x in self.actions.list_actions()]
|
||||
|
||||
# no actions set yet to panels or toolbars
|
||||
self.toolbars = {}
|
||||
self.panels = []
|
||||
|
||||
def config_load(self, widget):
|
||||
# user loads a new configuration?
|
||||
if self.callbacks.config_load(widget):
|
||||
print("TODO: reset toggle actions")
|
||||
|
||||
# ----- toolbar / panel additions ---------
|
||||
def set_actions(self, action_str, place):
|
||||
"set_actions(actions,place) -> error string, None if all OK"
|
||||
actions = action_str.split(",")
|
||||
for action in actions:
|
||||
if action in self.action_names:
|
||||
# regular action
|
||||
continue
|
||||
if action in self.panels:
|
||||
# user specified panel
|
||||
continue
|
||||
if action in ("close", ">"):
|
||||
if place != "panel":
|
||||
return "'close' and '>' can be only in a panel"
|
||||
continue
|
||||
if action == "|":
|
||||
# divider
|
||||
continue
|
||||
if action.find("=") >= 0:
|
||||
# special keycode/string action
|
||||
continue
|
||||
return "unrecognized action '%s'" % action
|
||||
|
||||
if place in ("left", "right", "top", "bottom"):
|
||||
self.toolbars[place] = actions
|
||||
return None
|
||||
if place == "panel":
|
||||
if len(actions) < 3:
|
||||
return "panel has too few items to be useful"
|
||||
return None
|
||||
return "unknown actions position '%s'" % place
|
||||
|
||||
def add_panel(self, spec):
|
||||
"add_panel(panel_specification) -> error string, None if all is OK"
|
||||
offset = spec.find(",")
|
||||
if offset <= 0:
|
||||
return "invalid panel specification '%s'" % spec
|
||||
|
||||
name, panelcontrols = spec[:offset], spec[offset+1:]
|
||||
error = self.set_actions(panelcontrols, "panel")
|
||||
if error:
|
||||
return error
|
||||
|
||||
if ",>," in panelcontrols:
|
||||
box = gtk.VBox()
|
||||
splitcontrols = panelcontrols.split(",>,")
|
||||
for controls in splitcontrols:
|
||||
box.add(self._get_container(controls.split(",")))
|
||||
else:
|
||||
box = self._get_container(panelcontrols.split(","))
|
||||
|
||||
self.panels.append(name)
|
||||
self.actions.add_actions(
|
||||
((name, gtk.STOCK_ADD, name, None, name, self.callbacks.panel),),
|
||||
box
|
||||
)
|
||||
return None
|
||||
|
||||
def list_actions(self):
|
||||
yield ("|", "Separator between controls")
|
||||
yield (">", "Start next toolbar row in panel windows")
|
||||
# generate the list from action information
|
||||
for act in self.actions.list_actions():
|
||||
note = act.get_property("tooltip")
|
||||
if not note:
|
||||
note = act.get_property("label")
|
||||
yield(act.get_name(), note)
|
||||
yield ("<panel name>", "Button for the specified panel window")
|
||||
yield ("<name>=<string/code>", "Synthetize string or single key <code>")
|
||||
|
||||
# ------- panel special actions -----------
|
||||
def _close_cb(self, widget):
|
||||
widget.get_toplevel().hide()
|
||||
|
||||
# ------- key special action -----------
|
||||
def _create_key_control(self, name, textcode):
|
||||
"Simulate Atari key press/release and string inserting"
|
||||
if not textcode:
|
||||
return None
|
||||
widget = gtk.ToolButton(gtk.STOCK_PASTE)
|
||||
widget.set_label(name)
|
||||
try:
|
||||
# part after "=" converts to an int?
|
||||
code = int(textcode, 0)
|
||||
widget.connect("clicked", self.callbacks.keypress, code)
|
||||
tip = "keycode: %d" % code
|
||||
except ValueError:
|
||||
# no, assume a string macro is wanted instead
|
||||
widget.connect("clicked", self.callbacks.textinsert, textcode)
|
||||
tip = "string '%s'" % textcode
|
||||
widget.set_tooltip_text("Insert " + tip)
|
||||
return widget
|
||||
|
||||
def _get_container(self, actions, horiz = True):
|
||||
"return Gtk container with the specified actions or None for no actions"
|
||||
if not actions:
|
||||
return None
|
||||
|
||||
#print("ACTIONS:", actions)
|
||||
if len(actions) > 1:
|
||||
bar = gtk.Toolbar()
|
||||
if horiz:
|
||||
bar.set_orientation(gtk.ORIENTATION_HORIZONTAL)
|
||||
else:
|
||||
bar.set_orientation(gtk.ORIENTATION_VERTICAL)
|
||||
bar.set_style(gtk.TOOLBAR_BOTH)
|
||||
# disable overflow menu to get toolbar sized correctly for panels
|
||||
bar.set_show_arrow(False)
|
||||
else:
|
||||
bar = None
|
||||
|
||||
for action in actions:
|
||||
#print(action)
|
||||
offset = action.find("=")
|
||||
if offset >= 0:
|
||||
# handle "<name>=<keycode>" action specification
|
||||
name = action[:offset]
|
||||
text = action[offset+1:]
|
||||
widget = self._create_key_control(name, text)
|
||||
elif action == "|":
|
||||
widget = gtk.SeparatorToolItem()
|
||||
elif action == "close":
|
||||
if bar:
|
||||
widget = create_toolbutton(gtk.STOCK_CLOSE, self._close_cb)
|
||||
else:
|
||||
widget = create_button("Close", self._close_cb)
|
||||
else:
|
||||
widget = self.actions.get_action(action).create_tool_item()
|
||||
if not widget:
|
||||
continue
|
||||
if bar:
|
||||
if action != "|":
|
||||
widget.set_expand(True)
|
||||
bar.insert(widget, -1)
|
||||
if bar:
|
||||
return bar
|
||||
return widget
|
||||
|
||||
# ------------- handling menu -------------
|
||||
def _add_submenu(self, bar, title, items):
|
||||
submenu = gtk.Menu()
|
||||
for name in items:
|
||||
if name:
|
||||
action = self.actions.get_action(name)
|
||||
item = action.create_menu_item()
|
||||
else:
|
||||
item = gtk.SeparatorMenuItem()
|
||||
submenu.add(item)
|
||||
baritem = gtk.MenuItem(title, False)
|
||||
baritem.set_submenu(submenu)
|
||||
bar.add(baritem)
|
||||
|
||||
def _get_menu(self):
|
||||
allmenus = (
|
||||
("File", ("load", "save", None, "shot", "recanim", "recsound", None, "quit")),
|
||||
("Emulation", ("run", "pause", "forward", None, "full", None, "input", None, "reset")),
|
||||
("Devices", ("display", "floppy", "harddisk", "joystick", "machine", "device", "sound")),
|
||||
("Configuration", ("path", None, "lconfig", "sconfig")),
|
||||
("Debug", ("debug", "trace")),
|
||||
("Help", ("manual", "compatibility", "release", "todo", None, "mails", "changes", None, "authors", "hatari", "hatariui", "about",))
|
||||
)
|
||||
bar = gtk.MenuBar()
|
||||
|
||||
for title, items in allmenus:
|
||||
self._add_submenu(bar, title, items)
|
||||
|
||||
if self.panels:
|
||||
self._add_submenu(bar, "Panels", self.panels)
|
||||
|
||||
return bar
|
||||
|
||||
# ------------- run the whole UI -------------
|
||||
def run(self, floppy, havemenu, fullscreen, embed):
|
||||
accelgroup = None
|
||||
# create menu?
|
||||
if havemenu:
|
||||
# this would steal keys from embedded Hatari
|
||||
if not embed:
|
||||
accelgroup = gtk.AccelGroup()
|
||||
for action in self.actions.list_actions():
|
||||
action.set_accel_group(accelgroup)
|
||||
menu = self._get_menu()
|
||||
else:
|
||||
menu = None
|
||||
|
||||
# create toolbars
|
||||
toolbars = { "left":None, "right":None, "top":None, "bottom":None}
|
||||
for side in ("left", "right"):
|
||||
if side in self.toolbars:
|
||||
toolbars[side] = self._get_container(self.toolbars[side], False)
|
||||
for side in ("top", "bottom"):
|
||||
if side in self.toolbars:
|
||||
toolbars[side] = self._get_container(self.toolbars[side], True)
|
||||
|
||||
self.callbacks.create_ui(accelgroup, menu, toolbars, fullscreen, embed)
|
||||
self.help.set_mainwin(self.callbacks.mainwin)
|
||||
self.callbacks.set_floppy(floppy)
|
||||
|
||||
# ugly, Hatari socket window ID can be gotten only
|
||||
# after Socket window is realized by gtk_main()
|
||||
gobject.idle_add(self.callbacks.run)
|
||||
gtk.main()
|
||||
|
||||
|
||||
# ------------- usage / argument handling --------------
|
||||
def usage(actions, msg=None):
|
||||
name = os.path.basename(sys.argv[0])
|
||||
uiname = "%s %s" % (UInfo.name, UInfo.version)
|
||||
print("\n%s" % uiname)
|
||||
print("=" * len(uiname))
|
||||
print("\nUsage: %s [options] [directory|disk image|Atari program]" % name)
|
||||
print("\nOptions:")
|
||||
print("\t-h, --help\t\tthis help")
|
||||
print("\t-n, --nomenu\t\tomit menus")
|
||||
print("\t-e, --embed\t\tembed Hatari window in middle of controls")
|
||||
print("\t-f, --fullscreen\tstart in fullscreen")
|
||||
print("\t-l, --left <controls>\ttoolbar at left")
|
||||
print("\t-r, --right <controls>\ttoolbar at right")
|
||||
print("\t-t, --top <controls>\ttoolbar at top")
|
||||
print("\t-b, --bottom <controls>\ttoolbar at bottom")
|
||||
print("\t-p, --panel <name>,<controls>")
|
||||
print("\t\t\t\tseparate window with given name and controls")
|
||||
print("\nAvailable (panel/toolbar) controls:")
|
||||
for action, description in actions.list_actions():
|
||||
size = len(action)
|
||||
if size < 8:
|
||||
tabs = "\t\t"
|
||||
elif size < 16:
|
||||
tabs = "\t"
|
||||
else:
|
||||
tabs = "\n\t\t\t"
|
||||
print("\t%s%s%s" % (action, tabs, description))
|
||||
print("""
|
||||
You can have as many panels as you wish. For each panel you need to add
|
||||
a control with the name of the panel (see "MyPanel" below).
|
||||
|
||||
For example:
|
||||
\t%s --embed \\
|
||||
\t-t "about,run,pause,quit" \\
|
||||
\t-p "MyPanel,Macro=Test,Undo=97,Help=98,>,F1=59,F2=60,F3=61,F4=62,>,close" \\
|
||||
\t-r "paste,debug,trace,machine,MyPanel" \\
|
||||
\t-b "sound,|,fastforward,|,fullscreen"
|
||||
|
||||
if no options are given, the UI uses basic controls.
|
||||
""" % name)
|
||||
if msg:
|
||||
print("ERROR: %s\n" % msg)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def main():
|
||||
info = UInfo()
|
||||
actions = UIActions()
|
||||
try:
|
||||
longopts = ["embed", "fullscreen", "nomenu", "help",
|
||||
"left=", "right=", "top=", "bottom=", "panel="]
|
||||
opts, floppies = getopt.getopt(sys.argv[1:], "efnhl:r:t:b:p:", longopts)
|
||||
del longopts
|
||||
except getopt.GetoptError as err:
|
||||
usage(actions, err)
|
||||
|
||||
menu = True
|
||||
embed = False
|
||||
fullscreen = False
|
||||
|
||||
error = None
|
||||
for opt, arg in opts:
|
||||
print(opt, arg)
|
||||
if opt in ("-e", "--embed"):
|
||||
embed = True
|
||||
elif opt in ("-f", "--fullscreen"):
|
||||
fullscreen = True
|
||||
elif opt in ("-n", "--nomenu"):
|
||||
menu = False
|
||||
elif opt in ("-h", "--help"):
|
||||
usage(actions)
|
||||
elif opt in ("-l", "--left"):
|
||||
error = actions.set_actions(arg, "left")
|
||||
elif opt in ("-r", "--right"):
|
||||
error = actions.set_actions(arg, "right")
|
||||
elif opt in ("-t", "--top"):
|
||||
error = actions.set_actions(arg, "top")
|
||||
elif opt in ("-b", "--bottom"):
|
||||
error = actions.set_actions(arg, "bottom")
|
||||
elif opt in ("-p", "--panel"):
|
||||
error = actions.add_panel(arg)
|
||||
else:
|
||||
assert False, "getopt returned unhandled option"
|
||||
if error:
|
||||
usage(actions, error)
|
||||
|
||||
if len(floppies) > 1:
|
||||
usage(actions, "multiple floppy images given: %s" % str(floppies))
|
||||
if floppies:
|
||||
if not os.path.exists(floppies[0]):
|
||||
usage(actions, "floppy image '%s' doesn't exist" % floppies[0])
|
||||
|
||||
actions.run(floppies, menu, fullscreen, embed)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
111
python-ui/release-notes.txt
Normal file
@ -0,0 +1,111 @@
|
||||
|
||||
User visible changes in Hatari (Python Gtk) UI
|
||||
----------------------------------------------
|
||||
|
||||
2015-05:
|
||||
- Add support for --gemdos-drive, --ttram option features
|
||||
and new tracepoints
|
||||
- Debugger window supports WinUAE CPU core
|
||||
- Updated UI version to 1.3
|
||||
|
||||
2014-06:
|
||||
- Add support for --sound-sync, --sound-buffer-size,
|
||||
--slowdown, --gemdos-case, --drive-*-heads and
|
||||
--drive-* option features and new tracepoints
|
||||
- Improved option names & descriptions
|
||||
- update UI version to 1.2
|
||||
|
||||
2012-05:
|
||||
- Add --desktop-st and --force-max options support
|
||||
(latter helps video recording of Falcon demos
|
||||
doing lots of resolution changes)
|
||||
|
||||
2012-01:
|
||||
- Add microphone and YM voice mixing sound options
|
||||
- Fix asserts and empty hatari config file caused by
|
||||
Hatari v1.6 config variable names changes by changing
|
||||
how Hatari config variable types are handled
|
||||
- Update UI version to v1.1 (mainly due to config change)
|
||||
- Support spaces in file paths/names
|
||||
|
||||
2011-10:
|
||||
- Replace --slowfdc with --fastfdc
|
||||
|
||||
2011-04:
|
||||
- Support RTC and "keep desktop resolution" options
|
||||
|
||||
2011-02:
|
||||
- Support new tracepoints (AES, DSP, Videl, Crossbar)
|
||||
- Disasm update for new Hatari disassembly output
|
||||
|
||||
2011-01:
|
||||
- Use new Gtk v2.12 tooltip API
|
||||
- Support capture cropping
|
||||
|
||||
2010-10:
|
||||
- Improvements to text & key inserting
|
||||
- Move hatari-console.py elsewhere
|
||||
|
||||
2010-05:
|
||||
- Manual page for Hatari UI
|
||||
|
||||
2010-04:
|
||||
- UI handles Hatari system configuration properly
|
||||
- New settings dialog for HD dir and image configuration
|
||||
- Maximum/preferred zoom support to display settings dialog
|
||||
- Removed --spec512 support
|
||||
- Option for whether debugger will change to new PC address
|
||||
whenever emulation is stopped again
|
||||
|
||||
2010-03:
|
||||
- With the new Hatari --saveconfig option Hatari UI can ask Hatari
|
||||
to save its configuration (required by the UI) before the UI itself
|
||||
starts, user doesn't need to do it manually anymore
|
||||
(if user config is missing or out of date)
|
||||
- Added --slowfdc support to Floppy settings dialog
|
||||
|
||||
2009-09:
|
||||
- Support for setting CPU level & clock and Falcon DSP type
|
||||
|
||||
2009-08:
|
||||
- Update to latest Hatari 1.3.0:
|
||||
- Debug/trace fixes (Hatari 1.3.1 includes these)
|
||||
|
||||
2009-07:
|
||||
- Add Help menu items pointing to Hatari docs & site
|
||||
- --timer-d support + doc updates
|
||||
|
||||
2009-06:
|
||||
- Move to BerliOS Hatari repo
|
||||
- Update to latest Hatari 1.2.0:
|
||||
- midi in/out, sound freq etc
|
||||
|
||||
2008-10:
|
||||
- Support paths & peripherals settings
|
||||
|
||||
2008-09:
|
||||
- Support for auto frameskip, statusbar and overlay led
|
||||
- Remove support for multiple machine setups
|
||||
(now that run-time Hatari config/saving loading works)
|
||||
|
||||
2008-07:
|
||||
- Support recanim/sound, config load/save and memory snapshot load/save
|
||||
- First properly working with menus and toolbars instead of buttons
|
||||
- Can adapt properly also to Hatari window getting smaller
|
||||
(works on desktop, maemo/Matchbox WM have still issues)
|
||||
- Makefile for installation
|
||||
|
||||
2008-06:
|
||||
- Fairly usable version with configurable buttons
|
||||
- Can adapt to Hatari window size changes
|
||||
|
||||
2008-05:
|
||||
- Loading & saving Hatari configuration and checking
|
||||
changes against saved configuration works
|
||||
|
||||
2008-04:
|
||||
- First version with debugger UI
|
||||
|
||||
2008-02:
|
||||
- First version that can embed Hatari window (needed quite
|
||||
a lot of testing to find method that works well enough)
|
6
python-ui/tests/README
Normal file
@ -0,0 +1,6 @@
|
||||
|
||||
Files
|
||||
-----
|
||||
|
||||
pygtk-hatari-embed-test.py -- Several tries at embedding Hatari window
|
||||
pygtk-hello-world.py -- simplest PyGtk program
|
200
python-ui/tests/pygtk-hatari-embed-test.py
Normal file
@ -0,0 +1,200 @@
|
||||
#!/usr/bin/python
|
||||
#
|
||||
# Tests embedding hatari with three different methods:
|
||||
# "hatari": ask Hatari to reparent to given window
|
||||
# "sdl": Give SDL window into which it should reparent
|
||||
# -> SDL doesn't handle (mouse, key, expose) events
|
||||
# although according to "xev" it's window receives them!
|
||||
# Bug in SDL (not one of the originally needed features?)?
|
||||
# "reparent": Find Hatari window and reparent it into pygtk widget in python
|
||||
# - Needs "xwininfo" and "awk"
|
||||
#
|
||||
# Using three alternative widgets:
|
||||
# "drawingarea"
|
||||
# "eventbox"
|
||||
# "socket"
|
||||
#
|
||||
# Results:
|
||||
# reparent+eventbox
|
||||
# -> PyGtk reparents Hatari under something on rootwindow instead
|
||||
# (reparening eventbox under Hatari window works fine though...)
|
||||
# reparent+socket
|
||||
# -> Hatari seems to be reparented back to where it was
|
||||
# sdl+anything
|
||||
# -> all events are lost
|
||||
# hatari+socket
|
||||
# -> seems to work fine
|
||||
import os
|
||||
import sys
|
||||
import gtk
|
||||
import time
|
||||
import gobject
|
||||
|
||||
def usage(error):
|
||||
print "\nusage: %s <widget> <embed method>\n" % sys.argv[0].split(os.path.sep)[-1]
|
||||
print "Opens window with given <widget>, runs Hatari and tries to embed it"
|
||||
print "with given <method>\n"
|
||||
print "<widget> can be <drawingarea|eventbox|socket>"
|
||||
print "<method> can be <sdl|hatari|reparent>\n"
|
||||
print "ERROR: %s\n" % error
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
class AppUI():
|
||||
hatari_wd = 640
|
||||
hatari_ht = 400
|
||||
|
||||
def __init__(self, widget, method):
|
||||
if method in ("hatari", "reparent", "sdl"):
|
||||
self.method = method
|
||||
else:
|
||||
usage("unknown <method> '%s'" % method)
|
||||
if widget == "drawingarea":
|
||||
widgettype = gtk.DrawingArea
|
||||
elif widget == "eventbox":
|
||||
widgettype = gtk.EventBox
|
||||
elif widget == "socket":
|
||||
# XEMBED socket for Hatari/SDL
|
||||
widgettype = gtk.Socket
|
||||
else:
|
||||
usage("unknown <widget> '%s'" % widget)
|
||||
self.window = self.create_window()
|
||||
self.add_hatari_parent(self.window, widgettype)
|
||||
gobject.timeout_add(1*1000, self.timeout_cb)
|
||||
|
||||
def create_window(self):
|
||||
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
|
||||
window.connect("destroy", self.do_quit)
|
||||
return window
|
||||
|
||||
def do_quit(self, widget):
|
||||
if self.hatari_pid:
|
||||
os.kill(self.hatari_pid, 9)
|
||||
print "killed Hatari PID %d" % self.hatari_pid
|
||||
self.hatari_pid = 0
|
||||
gtk.main_quit()
|
||||
|
||||
def add_hatari_parent(self, parent, widgettype):
|
||||
# Note: CAN_FOCUS has to be set for the widget embedding Hatari
|
||||
# and *unset* for everything else, otherwise Hatari doesn't
|
||||
# receive *any* keyevents.
|
||||
self.hatari_pid = 0
|
||||
vbox = gtk.VBox()
|
||||
button = gtk.Button("Test Button")
|
||||
button.unset_flags(gtk.CAN_FOCUS)
|
||||
vbox.add(button)
|
||||
widget = widgettype()
|
||||
widget.set_size_request(self.hatari_wd, self.hatari_ht)
|
||||
widget.set_events(gtk.gdk.ALL_EVENTS_MASK)
|
||||
widget.set_flags(gtk.CAN_FOCUS)
|
||||
self.hatariparent = widget
|
||||
# TODO: when running 320x200, parent could be centered to here
|
||||
vbox.add(widget)
|
||||
# test focus
|
||||
label = gtk.Label("Test SpinButton:")
|
||||
vbox.add(label)
|
||||
spin = gtk.SpinButton()
|
||||
spin.set_range(0, 10)
|
||||
spin.set_digits(0)
|
||||
spin.set_numeric(True)
|
||||
spin.set_increments(1, 2)
|
||||
# otherwise Hatari doesn't receive keys!!!
|
||||
spin.unset_flags(gtk.CAN_FOCUS)
|
||||
vbox.add(spin)
|
||||
parent.add(vbox)
|
||||
|
||||
def timeout_cb(self):
|
||||
self.do_hatari_method()
|
||||
return False # only once
|
||||
|
||||
def do_hatari_method(self):
|
||||
pid = os.fork()
|
||||
if pid < 0:
|
||||
print "ERROR: fork()ing Hatari failed!"
|
||||
return
|
||||
if pid:
|
||||
# in parent
|
||||
if self.method == "reparent":
|
||||
hatari_win = self.find_hatari_window()
|
||||
if hatari_win:
|
||||
self.reparent_hatari_window(hatari_win)
|
||||
self.hatari_pid = pid
|
||||
else:
|
||||
os.kill(pid, signal.SIGKILL)
|
||||
print "killed process with PID %d" % pid
|
||||
self.hatari_pid = 0
|
||||
else:
|
||||
# method == "sdl" or "hatari"
|
||||
self.hatari_pid = pid
|
||||
else:
|
||||
# child runs Hatari
|
||||
args = ("hatari", "-m", "-z", "2")
|
||||
os.execvpe("hatari", args, self.get_hatari_env())
|
||||
|
||||
def get_hatari_env(self):
|
||||
if self.method == "reparent":
|
||||
return os.environ
|
||||
# tell SDL to use (embed itself inside) given widget's window
|
||||
win_id = self.hatariparent.window.xid
|
||||
env = os.environ
|
||||
if self.method == "sdl":
|
||||
env["SDL_WINDOWID"] = str(win_id)
|
||||
elif self.method == "hatari":
|
||||
env["HATARI_PARENT_WIN"] = str(win_id)
|
||||
return env
|
||||
|
||||
def find_hatari_window(self):
|
||||
# find hatari window by its WM class string and reparent it
|
||||
cmd = """xwininfo -root -tree|awk '/"hatari" "hatari"/{print $1}'"""
|
||||
counter = 0
|
||||
while counter < 8:
|
||||
pipe = os.popen(cmd)
|
||||
windows = []
|
||||
for line in pipe.readlines():
|
||||
windows.append(int(line, 16))
|
||||
try:
|
||||
pipe.close()
|
||||
except IOError:
|
||||
# handle child process exiting silently
|
||||
pass
|
||||
if not windows:
|
||||
counter += 1
|
||||
print "WARNING: no Hatari window found yet, retrying..."
|
||||
time.sleep(1)
|
||||
continue
|
||||
if len(windows) > 1:
|
||||
print "WARNING: multiple Hatari windows, picking first one..."
|
||||
return windows[0]
|
||||
print "ERROR: no windows with the 'hatari' WM class found"
|
||||
return None
|
||||
|
||||
def reparent_hatari_window(self, hatari_win):
|
||||
window = gtk.gdk.window_foreign_new(hatari_win)
|
||||
if not window:
|
||||
print "ERROR: Hatari window (ID: 0x%x) reparenting failed!" % hatari_win
|
||||
return False
|
||||
if not self.hatariparent.window:
|
||||
print "ERROR: where hatariparent disappeared?"
|
||||
return False
|
||||
print "Found Hatari window ID: 0x%x, reparenting..." % hatari_win
|
||||
print "...to container window ID: 0x%x" % self.hatariparent.window.xid
|
||||
window.reparent(self.hatariparent.window, 0, 0)
|
||||
#window.reparent(self.hatariparent.get_toplevel().window, 0, 0)
|
||||
#window.reparent(self.hatariparent.get_root_window(), 0, 0)
|
||||
#window.show()
|
||||
#window.raise_()
|
||||
# If python would destroy the Gtk widget when it goes out of scope,
|
||||
# the foreign window widget destructor would delete Hatari window.
|
||||
# So, keep a reference
|
||||
#self.hatariwindow = window
|
||||
return True
|
||||
|
||||
def run(self):
|
||||
self.window.show_all()
|
||||
gtk.main()
|
||||
|
||||
|
||||
if len(sys.argv) != 3:
|
||||
usage("wrong number of arguments")
|
||||
app = AppUI(sys.argv[1], sys.argv[2])
|
||||
app.run()
|
18
python-ui/tests/pygtk-hello-world.py
Normal file
@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import gtk
|
||||
|
||||
class AppUI():
|
||||
def __init__(self):
|
||||
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
|
||||
self.window.connect("destroy", gtk.main_quit)
|
||||
|
||||
label = gtk.Label("Hello World!")
|
||||
self.window.add(label)
|
||||
|
||||
def run(self):
|
||||
self.window.show_all()
|
||||
gtk.main()
|
||||
|
||||
app = AppUI()
|
||||
app.run()
|
417
python-ui/uihelpers.py
Normal file
@ -0,0 +1,417 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Misc common helper classes and functions for the Hatari UI
|
||||
#
|
||||
# Copyright (C) 2008-2012 by Eero Tamminen
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
import os
|
||||
import sys
|
||||
# use correct version of pygtk/gtk
|
||||
import pygtk
|
||||
pygtk.require('2.0')
|
||||
import gtk
|
||||
import gobject
|
||||
|
||||
|
||||
# leak debugging
|
||||
#import gc
|
||||
#gc.set_debug(gc.DEBUG_UNCOLLECTABLE)
|
||||
|
||||
|
||||
# ---------------------
|
||||
# Hatari UI information
|
||||
|
||||
class UInfo:
|
||||
"""singleton constants for the UI windows,
|
||||
one instance is needed to initialize these properly"""
|
||||
version = "v1.3"
|
||||
name = "Hatari UI"
|
||||
logo = "hatari-logo.png"
|
||||
# TODO: use share/icons/hicolor/*/apps/hatari.png instead
|
||||
icon = "hatari-icon.png"
|
||||
copyright = "UI copyright (C) 2008-2015 by Eero Tamminen"
|
||||
|
||||
# path to the directory where the called script resides
|
||||
path = os.path.dirname(sys.argv[0])
|
||||
|
||||
def __init__(self, path = None):
|
||||
"UIinfo([path]), set suitable paths for resources from CWD and path"
|
||||
if path:
|
||||
self.path = path
|
||||
if not os.path.exists(UInfo.icon):
|
||||
UInfo.icon = self._get_path(UInfo.icon)
|
||||
if not os.path.exists(UInfo.logo):
|
||||
UInfo.logo = self._get_path(UInfo.logo)
|
||||
|
||||
def _get_path(self, filename):
|
||||
sep = os.path.sep
|
||||
testpath = "%s%s%s" % (self.path, sep, filename)
|
||||
if os.path.exists(testpath):
|
||||
return testpath
|
||||
|
||||
|
||||
# --------------------------------------------------------
|
||||
# functions for showing HTML files
|
||||
|
||||
class UIHelp:
|
||||
def __init__(self):
|
||||
"""determine HTML viewer and where docs are"""
|
||||
self._view = self.get_html_viewer()
|
||||
self._path = self.get_doc_path()
|
||||
|
||||
def get_html_viewer(self):
|
||||
"""return name of html viewer or None"""
|
||||
path = self.get_binary_path("xdg-open")
|
||||
if path:
|
||||
return path
|
||||
path = self.get_binary_path("firefox")
|
||||
if path:
|
||||
return path
|
||||
return None
|
||||
|
||||
def get_binary_path(self, name):
|
||||
"""return true if given binary is in path"""
|
||||
# could also try running the binary with "--version" arg
|
||||
# and check the exec return value
|
||||
if os.sys.platform == "win32":
|
||||
splitter = ';'
|
||||
else:
|
||||
splitter = ':'
|
||||
for i in os.environ['PATH'].split(splitter):
|
||||
fname = os.path.join(i, name)
|
||||
if os.access(fname, os.X_OK) and not os.path.isdir(fname):
|
||||
return fname
|
||||
return None
|
||||
|
||||
def get_doc_path(self):
|
||||
"""return path or URL to Hatari docs or None"""
|
||||
# first try whether there are local Hatari docs in standard place
|
||||
# for this Hatari/UI version
|
||||
sep = os.sep
|
||||
path = self.get_binary_path("hatari")
|
||||
path = sep.join(path.split(sep)[:-2]) # remove "bin/hatari"
|
||||
path = path + sep + "share" + sep + "doc" + sep + "hatari" + sep
|
||||
if os.path.exists(path + "manual.html"):
|
||||
return path
|
||||
# if not, point to latest Hatari HG version docs
|
||||
print("WARNING: Hatari manual not found at:", path + "manual.html")
|
||||
return "http://hg.tuxfamily.org/mercurialroot/hatari/hatari/raw-file/tip/doc/"
|
||||
|
||||
def set_mainwin(self, widget):
|
||||
self.mainwin = widget
|
||||
|
||||
def view_url(self, url, name):
|
||||
"""view given URL or file path, or error use 'name' as its name"""
|
||||
if self._view and "://" in url or os.path.exists(url):
|
||||
print("RUN: '%s' '%s'" % (self._view, url))
|
||||
os.spawnlp(os.P_NOWAIT, self._view, self._view, url)
|
||||
return
|
||||
if not self._view:
|
||||
msg = "Cannot view %s, HTML viewer missing" % name
|
||||
else:
|
||||
msg = "Cannot view %s,\n'%s' file is missing" % (name, url)
|
||||
from dialogs import ErrorDialog
|
||||
ErrorDialog(self.mainwin).run(msg)
|
||||
|
||||
def view_hatari_manual(self, dummy=None):
|
||||
self.view_url(self._path + "manual.html", "Hatari manual")
|
||||
|
||||
def view_hatari_compatibility(self, dummy=None):
|
||||
self.view_url(self._path + "compatibility.html", "Hatari compatibility list")
|
||||
|
||||
def view_hatari_releasenotes(self, dummy=None):
|
||||
self.view_url(self._path + "release-notes.txt", "Hatari release notes")
|
||||
|
||||
def view_hatari_todo(self, dummy=None):
|
||||
self.view_url(self._path + "todo.txt", "Hatari TODO items")
|
||||
|
||||
def view_hatari_mails(self, dummy=None):
|
||||
self.view_url("http://hatari.tuxfamily.org/contact.html", "Hatari mailing lists")
|
||||
|
||||
def view_hatari_repository(self, dummy=None):
|
||||
self.view_url("http://hg.tuxfamily.org/mercurialroot/hatari/hatari", "latest Hatari changes")
|
||||
|
||||
def view_hatari_authors(self, dummy=None):
|
||||
self.view_url(self._path + "authors.txt", "Hatari authors")
|
||||
|
||||
def view_hatari_page(self, dummy=None):
|
||||
self.view_url("http://hatari.tuxfamily.org/", "Hatari home page")
|
||||
|
||||
def view_hatariui_page(self, dummy=None):
|
||||
self.view_url("http://koti.mbnet.fi/tammat/hatari/hatari-ui.shtml", "Hatari UI home page")
|
||||
|
||||
|
||||
# --------------------------------------------------------
|
||||
# auxiliary class+callback to be used with the PasteDialog
|
||||
|
||||
class HatariTextInsert:
|
||||
def __init__(self, hatari, text):
|
||||
self.index = 0
|
||||
self.text = text
|
||||
self.pressed = False
|
||||
self.hatari = hatari
|
||||
print("OUTPUT '%s'" % text)
|
||||
gobject.timeout_add(100, _text_insert_cb, self)
|
||||
|
||||
# callback to insert text object to Hatari character at the time
|
||||
# (first key down, on next call up), at given interval
|
||||
def _text_insert_cb(textobj):
|
||||
char = textobj.text[textobj.index]
|
||||
if char == ' ':
|
||||
# white space gets stripped, use scancode instead
|
||||
char = "57"
|
||||
if textobj.pressed:
|
||||
textobj.pressed = False
|
||||
textobj.hatari.insert_event("keyup %s" % char)
|
||||
textobj.index += 1
|
||||
if textobj.index >= len(textobj.text):
|
||||
del(textobj)
|
||||
return False
|
||||
else:
|
||||
textobj.pressed = True
|
||||
textobj.hatari.insert_event("keydown %s" % char)
|
||||
# call again
|
||||
return True
|
||||
|
||||
|
||||
# ----------------------------
|
||||
# helper functions for buttons
|
||||
|
||||
def create_button(label, cb, data = None):
|
||||
"create_button(label,cb[,data]) -> button widget"
|
||||
button = gtk.Button(label)
|
||||
if data == None:
|
||||
button.connect("clicked", cb)
|
||||
else:
|
||||
button.connect("clicked", cb, data)
|
||||
return button
|
||||
|
||||
def create_toolbutton(stock_id, cb, data = None):
|
||||
"create_toolbutton(stock_id,cb[,data]) -> toolbar button with stock icon+label"
|
||||
button = gtk.ToolButton(stock_id)
|
||||
if data == None:
|
||||
button.connect("clicked", cb)
|
||||
else:
|
||||
button.connect("clicked", cb, data)
|
||||
return button
|
||||
|
||||
def create_toggle(label, cb, data = None):
|
||||
"create_toggle(label,cb[,data]) -> toggle button widget"
|
||||
button = gtk.ToggleButton(label)
|
||||
if data == None:
|
||||
button.connect("toggled", cb)
|
||||
else:
|
||||
button.connect("toggled", cb, data)
|
||||
return button
|
||||
|
||||
|
||||
# -----------------------------
|
||||
# Table dialog helper functions
|
||||
|
||||
def create_table_dialog(parent, title, rows, cols, oktext = gtk.STOCK_APPLY):
|
||||
"create_table_dialog(parent,title,rows, cols, oktext) -> (table,dialog)"
|
||||
dialog = gtk.Dialog(title, parent,
|
||||
gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
|
||||
(oktext, gtk.RESPONSE_APPLY,
|
||||
gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
|
||||
|
||||
table = gtk.Table(rows, cols)
|
||||
table.set_data("col_offset", 0)
|
||||
table.set_col_spacings(8)
|
||||
dialog.vbox.add(table)
|
||||
return (table, dialog)
|
||||
|
||||
def table_set_col_offset(table, offset):
|
||||
"set column offset for successive table_* ops on given table"
|
||||
table.set_data("col_offset", offset)
|
||||
|
||||
def table_add_entry_row(table, row, label, size = None):
|
||||
"table_add_entry_row(table,row,label,[entry size]) -> entry"
|
||||
# add given label to given row in given table
|
||||
# return entry for that line
|
||||
label = gtk.Label(label)
|
||||
align = gtk.Alignment(1) # right aligned
|
||||
align.add(label)
|
||||
col = table.get_data("col_offset")
|
||||
table.attach(align, col, col+1, row, row+1, gtk.FILL)
|
||||
col += 1
|
||||
if size:
|
||||
entry = gtk.Entry(size)
|
||||
entry.set_width_chars(size)
|
||||
align = gtk.Alignment(0) # left aligned (default is centered)
|
||||
align.add(entry)
|
||||
table.attach(align, col, col+1, row, row+1)
|
||||
else:
|
||||
entry = gtk.Entry()
|
||||
table.attach(entry, col, col+1, row, row+1)
|
||||
return entry
|
||||
|
||||
def table_add_widget_row(table, row, label, widget, fullspan = False):
|
||||
"table_add_widget_row(table,row,label,widget) -> widget"
|
||||
# add given label right aligned to given row in given table
|
||||
# add given widget to the right column and returns it
|
||||
# return entry for that line
|
||||
if fullspan:
|
||||
col = 0
|
||||
else:
|
||||
col = table.get_data("col_offset")
|
||||
if label:
|
||||
label = gtk.Label(label)
|
||||
align = gtk.Alignment(1)
|
||||
align.add(label)
|
||||
table.attach(align, col, col+1, row, row+1, gtk.FILL)
|
||||
if fullspan:
|
||||
col = table.get_data("col_offset")
|
||||
table.attach(widget, 1, col+2, row, row+1)
|
||||
else:
|
||||
table.attach(widget, col+1, col+2, row, row+1)
|
||||
return widget
|
||||
|
||||
def table_add_radio_rows(table, row, label, texts, cb = None):
|
||||
"table_add_radio_rows(table,row,label,texts[,cb]) -> [radios]"
|
||||
# - add given label right aligned to given row in given table
|
||||
# - create/add radio buttons with given texts to next row, set
|
||||
# the one given as "active" as active and set 'cb' as their
|
||||
# "toggled" callback handler
|
||||
# - return array or radiobuttons
|
||||
label = gtk.Label(label)
|
||||
align = gtk.Alignment(1)
|
||||
align.add(label)
|
||||
col = table.get_data("col_offset")
|
||||
table.attach(align, col, col+1, row, row+1, gtk.FILL)
|
||||
|
||||
radios = []
|
||||
radio = None
|
||||
box = gtk.VBox()
|
||||
for text in texts:
|
||||
radio = gtk.RadioButton(radio, text)
|
||||
if cb:
|
||||
radio.connect("toggled", cb, text)
|
||||
radios.append(radio)
|
||||
box.add(radio)
|
||||
table.attach(box, col+1, col+2, row, row+1)
|
||||
return radios
|
||||
|
||||
def table_add_separator(table, row):
|
||||
"table_add_separator(table,row)"
|
||||
widget = gtk.HSeparator()
|
||||
endcol = table.get_data("n-columns")
|
||||
# separator for whole table width
|
||||
table.attach(widget, 0, endcol, row, row+1, gtk.FILL)
|
||||
|
||||
|
||||
# -----------------------------
|
||||
# File selection helpers
|
||||
|
||||
def get_open_filename(title, parent, path = None):
|
||||
buttons = (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
|
||||
fsel = gtk.FileChooserDialog(title, parent, gtk.FILE_CHOOSER_ACTION_OPEN, buttons)
|
||||
fsel.set_local_only(True)
|
||||
if path:
|
||||
fsel.set_filename(path)
|
||||
if fsel.run() == gtk.RESPONSE_OK:
|
||||
filename = fsel.get_filename()
|
||||
else:
|
||||
filename = None
|
||||
fsel.destroy()
|
||||
return filename
|
||||
|
||||
def get_save_filename(title, parent, path = None):
|
||||
buttons = (gtk.STOCK_OK, gtk.RESPONSE_OK, gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
|
||||
fsel = gtk.FileChooserDialog(title, parent, gtk.FILE_CHOOSER_ACTION_SAVE, buttons)
|
||||
fsel.set_local_only(True)
|
||||
fsel.set_do_overwrite_confirmation(True)
|
||||
if path:
|
||||
fsel.set_filename(path)
|
||||
if not os.path.exists(path):
|
||||
# above set only folder, this is needed to set
|
||||
# the file name when the file doesn't exist
|
||||
fsel.set_current_name(os.path.basename(path))
|
||||
if fsel.run() == gtk.RESPONSE_OK:
|
||||
filename = fsel.get_filename()
|
||||
else:
|
||||
filename = None
|
||||
fsel.destroy()
|
||||
return filename
|
||||
|
||||
|
||||
# File selection button with eject button
|
||||
class FselAndEjectFactory:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def get(self, label, path, filename, action):
|
||||
"returns file selection button and box having that + eject button"
|
||||
fsel = gtk.FileChooserButton(label)
|
||||
# Hatari cannot access URIs
|
||||
fsel.set_local_only(True)
|
||||
fsel.set_width_chars(12)
|
||||
fsel.set_action(action)
|
||||
if filename:
|
||||
fsel.set_filename(filename)
|
||||
elif path:
|
||||
fsel.set_current_folder(path)
|
||||
eject = create_button("Eject", self._eject, fsel)
|
||||
|
||||
box = gtk.HBox()
|
||||
box.pack_start(fsel)
|
||||
box.pack_start(eject, False, False)
|
||||
return (fsel, box)
|
||||
|
||||
def _eject(self, widget, fsel):
|
||||
fsel.unselect_all()
|
||||
|
||||
|
||||
# Gtk is braindead, there's no way to set a default filename
|
||||
# for file chooser button unless it already exists
|
||||
# - set_filename() works only for files that already exist
|
||||
# - set_current_name() works only for SAVE action,
|
||||
# but file chooser button doesn't support that
|
||||
# i.e. I had to do my own (less nice) container widget...
|
||||
class FselEntry:
|
||||
def __init__(self, parent, validate = None, data = None):
|
||||
self._parent = parent
|
||||
self._validate = validate
|
||||
self._validate_data = data
|
||||
entry = gtk.Entry()
|
||||
entry.set_width_chars(12)
|
||||
entry.set_editable(False)
|
||||
hbox = gtk.HBox()
|
||||
hbox.add(entry)
|
||||
button = create_button("Select...", self._select_file_cb)
|
||||
hbox.pack_start(button, False, False)
|
||||
self._entry = entry
|
||||
self._hbox = hbox
|
||||
|
||||
def _select_file_cb(self, widget):
|
||||
fname = self._entry.get_text()
|
||||
while True:
|
||||
fname = get_save_filename("Select file", self._parent, fname)
|
||||
if not fname:
|
||||
# assume cancel
|
||||
return
|
||||
if self._validate:
|
||||
# filename needs validation and is valid?
|
||||
if not self._validate(self._validate_data, fname):
|
||||
continue
|
||||
self._entry.set_text(fname)
|
||||
return
|
||||
|
||||
def set_filename(self, fname):
|
||||
self._entry.set_text(fname)
|
||||
|
||||
def get_filename(self):
|
||||
return self._entry.get_text()
|
||||
|
||||
def get_container(self):
|
||||
return self._hbox
|
255
readme.txt
Normal file
@ -0,0 +1,255 @@
|
||||
|
||||
|
||||
Hatari
|
||||
|
||||
Version 1.9, September 2015
|
||||
|
||||
http://hatari.tuxfamily.org/
|
||||
|
||||
|
||||
Contents:
|
||||
---------
|
||||
1. License
|
||||
2. What is Hatari?
|
||||
3. Compiling and installing
|
||||
3.1 WinUAE and "old" UAE CPU cores
|
||||
3.2 IPF support using capsimage library
|
||||
3.3 Notes for Linux distribution packagers
|
||||
3.3.1 Known distro problems
|
||||
4. Running Hatari
|
||||
5. Contact
|
||||
|
||||
|
||||
1) License
|
||||
----------
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Soft-
|
||||
ware Foundation; either version 2 of the License, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the
|
||||
Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston,
|
||||
MA 02110-1301, USA
|
||||
|
||||
Linking Hatari statically or dynamically with other modules is making a
|
||||
combined work based on Hatari. Thus, the terms and conditions of the GNU
|
||||
General Public License cover the whole combination.
|
||||
|
||||
In addition, as a special exception, the copyright holders of Hatari give you
|
||||
permission to combine Hatari with free software programs or libraries that are
|
||||
released under the GNU LGPL and with code included in the standard release
|
||||
of the IPF support library (a.k.a. libcapsimage, see http://www.softpres.org/
|
||||
for more information) under the Software Preservation Society Licence Agreement
|
||||
as it has been defined for IPF library version 4.2 and 5.1. Linking against modified
|
||||
versions of the IPF library is also allowed, as long as neither the license
|
||||
nor the purpose of the library (accessing .ipf or .ctr disk images) was changed.
|
||||
You may copy and distribute such a system following the terms of the GNU GPL
|
||||
for Hatari and the licenses of the other code concerned.
|
||||
|
||||
|
||||
2) What is Hatari?
|
||||
------------------
|
||||
|
||||
Hatari is an Atari ST/STE/TT/Falcon emulator for Linux, FreeBSD, NetBSD,
|
||||
BeOS, Mac-OSX and other Systems which are supported by the SDL library.
|
||||
Unlike most other open source ST emulators which try to give you a good
|
||||
environment for running GEM applications, Hatari tries to emulate the hardware
|
||||
as close as possible so that it is able to run most of the old Atari games
|
||||
and demos. Because of this, it may be somewhat slower than less accurate
|
||||
emulators.
|
||||
|
||||
|
||||
3) Compiling and installing
|
||||
---------------------------
|
||||
|
||||
For using Hatari, you need to have installed the following libraries:
|
||||
|
||||
Required:
|
||||
- The SDL library v1.2.10 or newer (http://www.libsdl.org)
|
||||
- The zlib compression library (http://www.gzip.org/zlib/)
|
||||
|
||||
Optional:
|
||||
- The PNG image library for PNG format screenshots and to decrease
|
||||
AVI video recording file sizes (http://www.libpng.org/)
|
||||
- The GNU Readline library for Hatari debugger command line editing
|
||||
- The Xlib library to support Hatari Python UI window embedding on
|
||||
systems with the X window system (Linux and other unixes)
|
||||
- The portaudio library for Falcon microphone handling
|
||||
- The IPF support library (http://www.softpres.org/download)
|
||||
|
||||
Don't forget to also install the header files of these libraries for compiling
|
||||
Hatari (some Linux distributions use separate development packages for these
|
||||
header files)!
|
||||
|
||||
For compiling Hatari, you need a C compiler (preferably GNU C), and a working
|
||||
CMake (v2.8 or newer) installation, see http://www.cmake.org/ for details.
|
||||
|
||||
CMake can generate makefiles for various flavours of "Make" (like GNU-Make)
|
||||
and various IDEs like Xcode on Mac OS X. To run CMake, you've got to pass the
|
||||
path to the sources of Hatari as parameter, for example run the following if
|
||||
you are in the topmost directory of the Hatari source tree:
|
||||
cmake .
|
||||
|
||||
If you're tracking Hatari version control, it's preferable to do
|
||||
the build in a separate build directory as above would overwrite
|
||||
the (non-CMake) Makefiles coming with Hatari:
|
||||
mkdir -p build
|
||||
cd build
|
||||
cmake ..
|
||||
|
||||
Have a look at the manual of CMake for other options. Alternatively, you can
|
||||
use the "cmake-gui" program to configure the sources with a graphical
|
||||
application or "ccmake" to configure them with ncurses UI.
|
||||
|
||||
For your convenience we also ship an old-fashioned configure script which can
|
||||
be used as a wrapper for running cmake. Type "./configure --help" to see the
|
||||
options of this script.
|
||||
|
||||
Assuming that you've used the Makefile generator of CMake, and cmake finished
|
||||
the configuration successfully, you can compile Hatari by typing "make". If all
|
||||
works fine, you'll get the executable "hatari" in the src/ subdirectory of the
|
||||
build tree. You can then install the emulator by typing "make install".
|
||||
|
||||
|
||||
3.1) WinUAE and "old" UAE CPU cores
|
||||
|
||||
By default Hatari is built with the "old" UAE CPU core used in the
|
||||
earlier Hatari releases, but versions starting from v1.5 support also
|
||||
new & experimental WinUAE CPU core which offers more cycle accurate
|
||||
030 & DSP emulation and from v1.6 onwards also working 030 MMU
|
||||
emulation.
|
||||
|
||||
The WinUAE CPU core can be enabled by toggling the ENABLE_WINUAE_CPU
|
||||
variable in the Hatari CMake configuration (e.g. with the interactive
|
||||
"ccmake" program). Alternatively, you can run "./configure
|
||||
--enable-winuae-cpu", which will run cmake with the correct
|
||||
parameters.
|
||||
|
||||
The plan is to eventually have WinUAE CPU core enabled by default and
|
||||
deprecate the "old" UAE CPU core, but currently WinUAE CPU core:
|
||||
- is lacking all the ST/STE specific tweaks and proper testing
|
||||
for ST/STE compatibility
|
||||
- despite better emulation, it still doesn't run all the Falcon
|
||||
programs that run with the "old" core although it works better
|
||||
for most of them
|
||||
- doesn't have full debugger support
|
||||
|
||||
It's recommended to use Hatari built with the "old" (default) UAE CPU
|
||||
core for ST/STE emulation and the new WinUAE core for Falcon emulation.
|
||||
And test also the old core if Falcon programs don't work with the new
|
||||
one...
|
||||
|
||||
|
||||
3.2) IPF support using capsimage library
|
||||
|
||||
Hatari can use the optionnal capsimage library to access IPF and CTR
|
||||
files. Those files are created using the Kryoflux board and allow to
|
||||
record MFM exact copies of original games, including the protection.
|
||||
|
||||
Version 4.2 of the library allows to access IPF files, while the more recent
|
||||
version 5.1 fixes some bugs, as well as adding support for CTR files.
|
||||
|
||||
Since version 5.1 is not yet available for all OSes in binary form, Hatari
|
||||
still default to version 4.2 (but you can compile capsimage 5.1 sources
|
||||
to build your library). You can change this by modifying "SET(CAPSIMAGE_VERSION 4)"
|
||||
into cmake/FindCapsImage.cmake
|
||||
|
||||
Refer to http://softpres.org/download and get the corresponding file
|
||||
from the "User Distribution" section that matches your OS.
|
||||
|
||||
For version 4.2, you should have the following files in your include path :
|
||||
/usr/local/include/caps/
|
||||
capsimage.h
|
||||
fdc.h
|
||||
form.h
|
||||
|
||||
For version 5.1, you should have the following files in your include path :
|
||||
/usr/local/include/caps5/
|
||||
CapsAPI.h
|
||||
CapsFDC.h
|
||||
CapsForm.h
|
||||
CapsLibAll.h
|
||||
CapsLib.h
|
||||
CapsLibVersion.h
|
||||
ComLib.h
|
||||
CommonTypes.h
|
||||
|
||||
You should also copy the libcapsimage.so* files in your library path,
|
||||
for example in /usr/local/lib/caps/ or /usr/local/lib/caps5/
|
||||
|
||||
|
||||
3.3) Notes for Linux distribution packagers
|
||||
|
||||
TOS tester in tests/tosboot/ directory can be used to verify that
|
||||
Hatari was built fine enough that it's able to boot all tested TOS
|
||||
versions in various different HW configurations and run some GEMDOS
|
||||
based tests. For EmuTOS, use version v0.8.7 or newer, older versions
|
||||
are buggy and fail the GEMDOS tests.
|
||||
|
||||
If Hatari package will have two application menu entries for Hatari,
|
||||
one for the Python UI embedding Hatari, and another one for the plain
|
||||
SDL version, the latter could open also a terminal window for Hatari
|
||||
command line debugger and its console messages:
|
||||
x-terminal-emulator -T "Hatari debug window, invoke debugger with AltGr+Pause" -e hatari
|
||||
|
||||
tools/hatari-tos-register.sh is a minimal example of Linux init script
|
||||
registering Hatari as a (binfmt_misc) handler for TOS binaries.
|
||||
|
||||
Alternatively one could add a mime type for TOS binaries with xdg-mime:
|
||||
http://portland.freedesktop.org/xdg-utils-1.0/xdg-mime.html
|
||||
But registering handlers for mime-types seems desktop specific.
|
||||
|
||||
|
||||
3.3.1) Known distro problems
|
||||
|
||||
Old RHEL 5 and the derived CentOS v5.x Linux distributions ship
|
||||
with a broken readline library:
|
||||
https://bugzilla.redhat.com/show_bug.cgi?id=499837
|
||||
|
||||
To get CMake readline detection and linking working on them,
|
||||
you need to give these as extra arguments to the "cmake" command:
|
||||
-DCMAKE_C_FLAGS=-lncurses -DCMAKE_EXE_LINKER_FLAGS=-lncurses
|
||||
|
||||
They also have too old Python/PyGtk version for the python based
|
||||
Hatari scripts. Here are patches for Hatari v1.5/v1.6 Python UI:
|
||||
http://listengine.tuxfamily.org/lists.tuxfamily.org/hatari-devel/2012/01/msg00008.html
|
||||
|
||||
|
||||
4) Running Hatari
|
||||
-----------------
|
||||
|
||||
For information about how to use the running emulator, please read the file
|
||||
doc/manual.html. Here are just some hints for the impatient people:
|
||||
|
||||
* Before you can run the emulator, you need a TOS ROM image. If one
|
||||
named as "tos.img" is neither in the data directory of the emulator
|
||||
(DATADIR variable in CMake configuration), or in the current
|
||||
directory, Hatari will ask you to select one.
|
||||
|
||||
- Hatari binary packages ship unmodified EmuTOS ROM image with them
|
||||
(renamed as tos.img), but you need an original Atari TOS ROM image
|
||||
for best compatibility. For more information on EmuTOS, see
|
||||
doc/emutos.txt.
|
||||
|
||||
* While the emulator is running, you can open the configuration menu
|
||||
by pressing F12, the F11 key will toggle fullscreen/windowed mode.
|
||||
Pressing ALTGR-q will quit the emulator.
|
||||
|
||||
|
||||
5) Contact
|
||||
----------
|
||||
|
||||
If you want to contact the authors of Hatari, please have a look at the file
|
||||
doc/authors.txt for the e-mail addresses or use the Hatari mailing list.
|
||||
|
||||
Visit the website of Hatari on Tuxfamily.org for more details:
|
||||
|
||||
http://hatari.tuxfamily.org/contact.html
|
||||
|
25
share/CMakeLists.txt
Normal file
@ -0,0 +1,25 @@
|
||||
|
||||
foreach(size 32x32 48x48 64x64 128x128 256x256)
|
||||
install(FILES icons/hicolor/${size}/apps/hatari.png
|
||||
DESTINATION ${ICONDIR}/${size}/apps)
|
||||
install(FILES icons/hicolor/${size}/mimetypes/application-x-st-disk-image.png
|
||||
DESTINATION ${ICONDIR}/${size}/mimetypes)
|
||||
foreach(type vnd.msa vnd.fastcopy x-stx)
|
||||
install(CODE "execute_process(COMMAND ln -sf application-x-st-disk-image.png
|
||||
${CMAKE_INSTALL_PREFIX}/${ICONDIR}/${size}/mimetypes/application-${type}-disk-image.png)
|
||||
")
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
install(FILES icons/hicolor/scalable/apps/hatari.svg
|
||||
DESTINATION ${ICONDIR}/scalable/apps)
|
||||
install(FILES icons/hicolor/scalable/mimetypes/application-x-st-disk-image.svg
|
||||
DESTINATION ${ICONDIR}/scalable/mimetypes)
|
||||
foreach(type vnd.msa vnd.fastcopy x-stx)
|
||||
install(CODE "execute_process(COMMAND ln -sf application-x-st-disk-image.svg
|
||||
${CMAKE_INSTALL_PREFIX}/${ICONDIR}/scalable/mimetypes/application-${type}-disk-image.svg)
|
||||
")
|
||||
endforeach()
|
||||
install(FILES mime/packages/hatari.xml DESTINATION share/mime/packages)
|
||||
|
||||
install(FILES applications/hatari.desktop DESTINATION share/applications)
|
11
share/applications/hatari.desktop
Normal file
@ -0,0 +1,11 @@
|
||||
[Desktop Entry]
|
||||
Version=1.0
|
||||
Type=Application
|
||||
Name=Hatari
|
||||
GenericName=ST emulator
|
||||
Comment=Run old ST/STE/TT/Falcon software
|
||||
Exec=hatari %f
|
||||
Icon=hatari
|
||||
MimeType=application/x-st-disk-image;application/vnd.msa-disk-image;application/vnd.fastcopy-disk-image;application/x-stx-disk-image
|
||||
Categories=Game;Emulator;
|
||||
Terminal=false
|
BIN
share/icons/hicolor/128x128/apps/hatari.png
Normal file
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 17 KiB |
BIN
share/icons/hicolor/256x256/apps/hatari.png
Normal file
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 48 KiB |
BIN
share/icons/hicolor/32x32/apps/hatari.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 1.6 KiB |
BIN
share/icons/hicolor/48x48/apps/hatari.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 2.9 KiB |
BIN
share/icons/hicolor/64x64/apps/hatari.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 4.7 KiB |
16
share/icons/hicolor/scalable/apps/hatari.svg
Normal file
After Width: | Height: | Size: 44 KiB |
@ -0,0 +1,63 @@
|
||||
<svg xmlns:osb="http://www.openswatchbook.org/uri/2009/osb" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" id="svg2" version="1.1" inkscape:version="0.48.4 r9939" width="256" height="256">
|
||||
<metadata id="metadata8">
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
||||
<dc:title/>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs id="defs6">
|
||||
<linearGradient id="linearGradient5300">
|
||||
<stop style="stop-color:#282850;stop-opacity:1;" offset="0" id="stop5302"/>
|
||||
<stop style="stop-color:#6060a0;stop-opacity:1;" offset="1" id="stop5304"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient5290">
|
||||
<stop style="stop-color:#000030;stop-opacity:1;" offset="0" id="stop5292"/>
|
||||
<stop style="stop-color:#101060;stop-opacity:1;" offset="1" id="stop5294"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient5280">
|
||||
<stop style="stop-color:#000032;stop-opacity:1;" offset="0" id="stop5282"/>
|
||||
<stop style="stop-color:#101040;stop-opacity:1;" offset="1" id="stop5284"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient5270">
|
||||
<stop style="stop-color:#404080;stop-opacity:1;" offset="0" id="stop5272"/>
|
||||
<stop style="stop-color:#000040;stop-opacity:1;" offset="1" id="stop5274"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient5241">
|
||||
<stop style="stop-color:#282840;stop-opacity:1;" offset="0" id="stop5243"/>
|
||||
<stop style="stop-color:#b4b4d0;stop-opacity:1;" offset="1" id="stop5245"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient5231">
|
||||
<stop style="stop-color:#000000;stop-opacity:1;" offset="0" id="stop5233"/>
|
||||
<stop style="stop-color:#404040;stop-opacity:1;" offset="1" id="stop5235"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient5221">
|
||||
<stop style="stop-color:#acacac;stop-opacity:1;" offset="0" id="stop5223"/>
|
||||
<stop style="stop-color:#202020;stop-opacity:1;" offset="1" id="stop5225"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient5209">
|
||||
<stop style="stop-color:#000000;stop-opacity:1;" offset="0" id="stop5211"/>
|
||||
<stop style="stop-color:#0060e0;stop-opacity:1;" offset="1" id="stop5213"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="linearGradient3769" osb:paint="solid">
|
||||
<stop style="stop-color:#00fb00;stop-opacity:1;" offset="0" id="stop3771"/>
|
||||
</linearGradient>
|
||||
<linearGradient inkscape:collect="always" xlink:href="#linearGradient5221" id="linearGradient5227" x1="69.9" y1="1.8" x2="191.9" y2="87.9" gradientUnits="userSpaceOnUse"/>
|
||||
<linearGradient inkscape:collect="always" xlink:href="#linearGradient5231" id="linearGradient5237" x1="141.2" y1="38.4" x2="176.3" y2="57.3" gradientUnits="userSpaceOnUse"/>
|
||||
<linearGradient inkscape:collect="always" xlink:href="#linearGradient5241" id="linearGradient5247" x1="41" y1="105.2" x2="221" y2="254.9" gradientUnits="userSpaceOnUse"/>
|
||||
<linearGradient inkscape:collect="always" xlink:href="#linearGradient5270" id="linearGradient5276" x1="9.9" y1="127.9" x2="249.8" y2="127.9" gradientUnits="userSpaceOnUse"/>
|
||||
<linearGradient inkscape:collect="always" xlink:href="#linearGradient5280" id="linearGradient5286" x1="32.6" y1="5.9" x2="195.2" y2="87.5" gradientUnits="userSpaceOnUse"/>
|
||||
<linearGradient inkscape:collect="always" xlink:href="#linearGradient5290" id="linearGradient5296" x1="17.5" y1="224.9" x2="29.3" y2="236.2" gradientUnits="userSpaceOnUse"/>
|
||||
<linearGradient inkscape:collect="always" xlink:href="#linearGradient5300" id="linearGradient5306" x1="17.4" y1="27.8" x2="25" y2="31.3" gradientUnits="userSpaceOnUse"/>
|
||||
</defs>
|
||||
<path style="color:#000000;fill:#000080;stroke:url(#linearGradient5276);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" d="m 13.8 1.7 18.4 0 3.1 4.6 6.9 0 2.7 -3.5 148 0 0.1 3.8 6.8 0 4.5 -4 33.1 0.2 11.9 13 0 234 -3.1 4.1 -232.4 0 -3.5 -4.6 0 -244.7 z" id="path5268" inkscape:connector-curvature="0"/>
|
||||
<path style="color:#000000;fill:none;stroke:url(#linearGradient5286);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" d="m 33.5 4.7 0.1 78.4 1.4 2.9 2.8 2 152.9 0 2.3 -2.5 1.9 -2.8 -0 -75.5" id="path5278" inkscape:connector-curvature="0"/>
|
||||
<path style="fill:#808080;stroke:url(#linearGradient5227);stroke-width:1.01021373px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" d="m 68.1 2.1 0 80.4 6.3 4.5 116.2 -0 3.5 -4.5 -0 -80.4 z" id="path5219" inkscape:connector-curvature="0"/>
|
||||
<path style="color:#000000;fill:#000080;stroke:url(#linearGradient5237);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" d="m 142.7 15.9 0.2 65.4 32 0 -0.4 -65.6 z" id="path5229" inkscape:connector-curvature="0"/>
|
||||
<path style="color:#000000;fill:#ececec;stroke:url(#linearGradient5247);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" d="m 40.7 106 176.8 -0.3 5.2 5.2 0.3 142.9 -186.8 0 0 -143.2 z" id="path5239" inkscape:connector-curvature="0"/>
|
||||
<rect style="fill:#000000;fill-rule:evenodd;stroke:url(#linearGradient5296);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" id="rect5288" width="13" height="10.3" x="16.8" y="225.4" ry="0.5"/>
|
||||
<path style="color:#000000;fill:none;stroke:url(#linearGradient5306);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" d="m 19.5 18.7 4 8.8 0 4 -2 -0 -0 7 -3.9 -0 -0 -6.9 -2 -0 0 -4 z" id="path5298" inkscape:connector-curvature="0"/>
|
||||
<path id="path5358" d="m 74.9 201.2 c 0 2.7 -0.7 7 1 9.3 2.3 3.1 8.5 3.4 12 3.9 11.4 1.9 29.2 1.4 34.4 -11.2 1.2 -2.8 1.6 -6 1.6 -9 -0 -24.9 -27.7 -13.5 -37.2 -28 -4.1 -6.3 1.4 -12.6 7.3 -14.8 8.5 -3.1 18.1 0.8 26 3.9 -0 -20.4 -39 -16.1 -44.2 1 -0.8 2.6 -0.9 5.3 -0.7 8 1.7 22 28.2 11.8 37.2 26 4 6.3 -1.1 13.5 -7.3 15.7 -10 3.7 -20.8 -1 -30 -4.7 m 55 -57 0 8 25 0 0 62 10 0 0 -62 25 0 0 -8 -60 0 z" style="fill:#ff0000;stroke:none" inkscape:connector-curvature="0"/>
|
||||
</svg>
|
After Width: | Height: | Size: 7.0 KiB |
32
share/mime/packages/hatari.xml
Normal file
@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
|
||||
<mime-type type="application/x-st-disk-image">
|
||||
<sub-class-of type="application/octet-stream"/>
|
||||
<comment>ST disk image</comment>
|
||||
<glob pattern="*.st"/>
|
||||
</mime-type>
|
||||
<mime-type type="application/vnd.msa-disk-image">
|
||||
<sub-class-of type="application/octet-stream"/>
|
||||
<comment>Magic Shadow Archiver disk image</comment>
|
||||
<glob pattern="*.msa"/>
|
||||
<magic priority="90">
|
||||
<match type="big16" offset="0" value="0x0E0F"/>
|
||||
</magic>
|
||||
</mime-type>
|
||||
<mime-type type="application/vnd.fastcopy-disk-image">
|
||||
<sub-class-of type="application/octet-stream"/>
|
||||
<comment>FastCopy DIM disk image</comment>
|
||||
<glob pattern="*.dim"/>
|
||||
<magic priority="90">
|
||||
<match type="big16" offset="0" value="0x4242"/>
|
||||
</magic>
|
||||
</mime-type>
|
||||
<mime-type type="application/x-stx-disk-image">
|
||||
<sub-class-of type="application/octet-stream"/>
|
||||
<comment>Pasti STX disk image</comment>
|
||||
<glob pattern="*.stx"/>
|
||||
<magic priority="90">
|
||||
<match type="big32" offset="0" value="0x52535900"/>
|
||||
</magic>
|
||||
</mime-type>
|
||||
</mime-info>
|