Update for v2.6.0

This commit is contained in:
Milan Nikolic 2024-10-09 16:39:46 +02:00
parent 101b504fdd
commit 234b811bd2
No known key found for this signature in database
GPG key ID: 9229D0EAA3AA4E75
13 changed files with 249 additions and 169 deletions

View file

@ -36,7 +36,7 @@ except ImportError as err:
sys.exit(1) sys.exit(1)
try: try:
from m64py.core.defs import FRONTEND_VERSION, LOGO from m64py.core.defs import FRONTEND_VERSION
except ImportError as err: except ImportError as err:
sys.stderr.write("Can't import m64py modules%sError:%s%s" % ( sys.stderr.write("Can't import m64py modules%sError:%s%s" % (
os.linesep, str(err), os.linesep)) os.linesep, str(err), os.linesep))
@ -51,8 +51,6 @@ def handle_exception(exc_type, exc_value, exc_traceback):
sys.excepthook = handle_exception sys.excepthook = handle_exception
if __name__ == "__main__": if __name__ == "__main__":
QApplication.setAttribute(Qt.AA_X11InitThreads)
app = QApplication(sys.argv) app = QApplication(sys.argv)
from m64py.opts import opts, args from m64py.opts import opts, args
@ -61,8 +59,8 @@ if __name__ == "__main__":
if translator.load(":i18n/m64py_" + locale, ":/"): if translator.load(":i18n/m64py_" + locale, ":/"):
app.installTranslator(translator) app.installTranslator(translator)
sys.stderr.write("%s\nM64Py - A frontend for Mupen64Plus version %s\n\n" % ( sys.stderr.write("M64Py - A frontend for Mupen64Plus version %s\n\n" % (
LOGO, FRONTEND_VERSION)) FRONTEND_VERSION))
from m64py.frontend.mainwindow import MainWindow from m64py.frontend.mainwindow import MainWindow
window = MainWindow((opts, args)) window = MainWindow((opts, args))

View file

@ -16,10 +16,8 @@
import os import os
import sys import sys
import signal
import ctypes as C
import subprocess
import binascii import binascii
import ctypes as C
from m64py.core.defs import * from m64py.core.defs import *
from m64py.core.config import Config from m64py.core.config import Config
@ -71,8 +69,8 @@ class Core:
self.plugins = {} self.plugins = {}
self.rom_type = None self.rom_type = None
self.rom_length = None self.rom_length = None
self.rom_header = m64p_rom_header() self.rom_header = M64pRomHeader()
self.rom_settings = m64p_rom_settings() self.rom_settings = M64pRomSettings()
self.core_path = "" self.core_path = ""
self.core_name = "Mupen64Plus Core" self.core_name = "Mupen64Plus Core"
self.core_version = "Unknown" self.core_version = "Unknown"
@ -127,6 +125,13 @@ class Core:
os.path.basename(self.core_path), os.path.basename(self.core_path),
version_split(config_ver), version_split(config_ver),
version_split(CONFIG_API_VERSION))) version_split(CONFIG_API_VERSION)))
if vidext_ver & 0xffff0000 != VIDEXT_API_VERSION & 0xffff0000:
raise Exception(
"emulator core '%s' is incompatible, "
"vidext API major version %s doesn't match application: (%s)" % (
os.path.basename(self.core_path),
version_split(config_ver),
version_split(CONFIG_API_VERSION)))
self.core_name = plugin_name self.core_name = plugin_name
self.core_version = plugin_version self.core_version = plugin_version
@ -291,7 +296,7 @@ class Core:
if rval != M64ERR_SUCCESS: if rval != M64ERR_SUCCESS:
log.debug("detach_plugins()") log.debug("detach_plugins()")
log.warn(self.error_message(rval)) log.warn(self.error_message(rval))
log.warn("core failed to dettach %s plugin." % ( log.warn("core failed to detach %s plugin." % (
plugin_name)) plugin_name))
def rom_open(self, romfile): def rom_open(self, romfile):
@ -478,7 +483,7 @@ class Core:
def get_rom_settings(self, crc1, crc2): def get_rom_settings(self, crc1, crc2):
"""Searches through the data in the ini file for given crc hashes, """Searches through the data in the ini file for given crc hashes,
if found, fills in the RomSettings structure with the data.""" if found, fills in the RomSettings structure with the data."""
rom_settings = m64p_rom_settings() rom_settings = M64pRomSettings()
rval = self.m64p.CoreGetRomSettings( rval = self.m64p.CoreGetRomSettings(
C.byref(rom_settings), C.byref(rom_settings),
C.c_int(C.sizeof(rom_settings)), C.c_int(C.sizeof(rom_settings)),

View file

@ -20,9 +20,10 @@ from m64py.platform import DLL_EXT
CORE_NAME = "mupen64plus" CORE_NAME = "mupen64plus"
CORE_API_VERSION = 0x20001 CORE_API_VERSION = 0x20001
CONFIG_API_VERSION = 0x20000 CONFIG_API_VERSION = 0x20302
MINIMUM_CORE_VERSION = 0x016300 VIDEXT_API_VERSION = 0x030300
FRONTEND_VERSION = "0.2.5" MINIMUM_CORE_VERSION = 0x020600
FRONTEND_VERSION = "0.2.6"
SIZE_1X = (320, 240) SIZE_1X = (320, 240)
SIZE_2X = (640, 480) SIZE_2X = (640, 480)
@ -69,6 +70,8 @@ M64VIDEO_NONE = 1
M64VIDEO_WINDOWED = 2 M64VIDEO_WINDOWED = 2
M64VIDEO_FULLSCREEN = 3 M64VIDEO_FULLSCREEN = 3
M64VIDEOFLAG_SUPPORT_RESIZING = 1
M64CORE_EMU_STATE = 1 M64CORE_EMU_STATE = 1
M64CORE_VIDEO_MODE = 2 M64CORE_VIDEO_MODE = 2
M64CORE_SAVESTATE_SLOT = 3 M64CORE_SAVESTATE_SLOT = 3
@ -80,6 +83,7 @@ M64CORE_AUDIO_MUTE = 8
M64CORE_INPUT_GAMESHARK = 9 M64CORE_INPUT_GAMESHARK = 9
M64CORE_STATE_LOADCOMPLETE = 10 M64CORE_STATE_LOADCOMPLETE = 10
M64CORE_STATE_SAVECOMPLETE = 11 M64CORE_STATE_SAVECOMPLETE = 11
M64CORE_SCREENSHOT_CAPTURED = 12
M64CMD_NOP = 0 M64CMD_NOP = 0
M64CMD_ROM_OPEN = 1 M64CMD_ROM_OPEN = 1
@ -102,6 +106,15 @@ M64CMD_CORE_STATE_SET = 17
M64CMD_READ_SCREEN = 18 M64CMD_READ_SCREEN = 18
M64CMD_RESET = 19 M64CMD_RESET = 19
M64CMD_ADVANCE_FRAME = 20 M64CMD_ADVANCE_FRAME = 20
M64CMD_SET_MEDIA_LOADER = 21
M64CMD_NETPLAY_INIT = 22
M64CMD_NETPLAY_CONTROL_PLAYER = 23
M64CMD_NETPLAY_GET_VERSION = 24
M64CMD_NETPLAY_CLOSE = 25
M64CMD_PIF_OPEN = 26
M64CMD_ROM_SET_SETTINGS = 27
M64CMD_DISK_OPEN = 28
M64CMD_DISK_CLOSE = 29
M64P_GL_DOUBLEBUFFER = 1 M64P_GL_DOUBLEBUFFER = 1
M64P_GL_BUFFER_SIZE = 2 M64P_GL_BUFFER_SIZE = 2
@ -117,6 +130,10 @@ M64P_GL_CONTEXT_MAJOR_VERSION = 11
M64P_GL_CONTEXT_MINOR_VERSION = 12 M64P_GL_CONTEXT_MINOR_VERSION = 12
M64P_GL_CONTEXT_PROFILE_MASK = 13 M64P_GL_CONTEXT_PROFILE_MASK = 13
M64P_GL_CONTEXT_PROFILE_CORE = 0
M64P_GL_CONTEXT_PROFILE_COMPATIBILITY = 1
M64P_GL_CONTEXT_PROFILE_ES = 2
M64TYPE_INT = 1 M64TYPE_INT = 1
M64TYPE_FLOAT = 2 M64TYPE_FLOAT = 2
M64TYPE_BOOL = 3 M64TYPE_BOOL = 3
@ -166,27 +183,28 @@ m64p_error = C.c_int
m64p_GLattr = C.c_int m64p_GLattr = C.c_int
class m64p_rom_header(C.Structure): class M64pRomHeader(C.Structure):
_fields_ = [ _fields_ = [
('init_PI_BSB_DOM1_LAT_REG', C.c_ubyte), ('init_PI_BSB_DOM1_LAT_REG', C.c_uint8),
('init_PI_BSB_DOM1_PGS_REG', C.c_ubyte), ('init_PI_BSB_DOM1_PGS_REG', C.c_uint8),
('init_PI_BSB_DOM1_PWD_REG', C.c_ubyte), ('init_PI_BSB_DOM1_PWD_REG', C.c_uint8),
('init_PI_BSB_DOM1_PGS_REG2', C.c_ubyte), ('init_PI_BSB_DOM1_PGS_REG2', C.c_uint8),
('ClockRate', C.c_uint), ('ClockRate', C.c_uint32),
('PC', C.c_uint), ('PC', C.c_uint32),
('Release', C.c_uint), ('Release', C.c_uint32),
('CRC1', C.c_uint), ('CRC1', C.c_uint32),
('CRC2', C.c_uint), ('CRC2', C.c_uint32),
('Unknown', C.c_uint * 2), ('Unknown', C.c_uint32 * 2),
('Name', C.c_char * 20), ('Name', C.c_char * 20),
('unknown', C.c_uint), ('unknown', C.c_uint32),
('Manufacturer_ID', C.c_uint), ('Manufacturer_ID', C.c_uint32),
('Cartridge_ID', C.c_ushort), ('Cartridge_ID', C.c_uint16),
('Country_code', C.c_ushort) ('Country_code', C.c_uint8),
('Version', C.c_uint8)
] ]
class m64p_rom_settings(C.Structure): class M64pRomSettings(C.Structure):
_fields_ = [ _fields_ = [
('goodname', C.c_char * 256), ('goodname', C.c_char * 256),
('MD5', C.c_char * 33), ('MD5', C.c_char * 33),
@ -196,18 +214,22 @@ class m64p_rom_settings(C.Structure):
('rumble', C.c_ubyte), ('rumble', C.c_ubyte),
('transferpak', C.c_ubyte), ('transferpak', C.c_ubyte),
('mempak', C.c_ubyte), ('mempak', C.c_ubyte),
('biopak', C.c_ubyte) ('biopak', C.c_ubyte),
('disableextramem', C.c_ubyte),
('countperop', C.c_uint),
('sidmaduration', C.c_uint),
('aidmamodifier', C.c_uint)
] ]
class m64p_cheat_code(C.Structure): class M64pCheatCode(C.Structure):
_fields_ = [ _fields_ = [
('address', C.c_uint), ('address', C.c_uint32),
('value', C.c_int), ('value', C.c_int),
] ]
class m64p_2d_size(C.Structure): class M64p2dSize(C.Structure):
_fields_ = [ _fields_ = [
('uiWidth', C.c_uint), ('uiWidth', C.c_uint),
('uiHeight', C.c_uint) ('uiHeight', C.c_uint)
@ -215,8 +237,10 @@ class m64p_2d_size(C.Structure):
FuncInit = C.CFUNCTYPE(m64p_error) FuncInit = C.CFUNCTYPE(m64p_error)
FuncQuit = C.CFUNCTYPE(m64p_error) FuncQuit = C.CFUNCTYPE(m64p_error)
FuncListModes = C.CFUNCTYPE(m64p_error, C.POINTER(m64p_2d_size), C.POINTER(C.c_int)) FuncListModes = C.CFUNCTYPE(m64p_error, C.POINTER(M64p2dSize), C.POINTER(C.c_int))
FuncSetMode = C.CFUNCTYPE(m64p_error, C.c_int, C.c_int, C.c_int, C.c_int) FuncListRates = C.CFUNCTYPE(m64p_error, M64p2dSize, C.POINTER(C.c_int), C.POINTER(C.c_int))
FuncSetMode = C.CFUNCTYPE(m64p_error, C.c_int, C.c_int, C.c_int, C.c_int, C.c_int)
FuncSetModeWithRate = C.CFUNCTYPE(m64p_error, C.c_int, C.c_int, C.c_int, C.c_int, C.c_int, C.c_int)
FuncGLGetProc = C.CFUNCTYPE(C.c_void_p, C.c_char_p) FuncGLGetProc = C.CFUNCTYPE(C.c_void_p, C.c_char_p)
FuncGLSetAttr = C.CFUNCTYPE(m64p_error, m64p_GLattr, C.c_int) FuncGLSetAttr = C.CFUNCTYPE(m64p_error, m64p_GLattr, C.c_int)
FuncGLGetAttr = C.CFUNCTYPE(m64p_error, m64p_GLattr, C.POINTER(C.c_int)) FuncGLGetAttr = C.CFUNCTYPE(m64p_error, m64p_GLattr, C.POINTER(C.c_int))
@ -224,16 +248,21 @@ FuncGLSwapBuf = C.CFUNCTYPE(m64p_error)
FuncSetCaption = C.CFUNCTYPE(m64p_error, C.c_char_p) FuncSetCaption = C.CFUNCTYPE(m64p_error, C.c_char_p)
FuncToggleFS = C.CFUNCTYPE(m64p_error) FuncToggleFS = C.CFUNCTYPE(m64p_error)
FuncResizeWindow = C.CFUNCTYPE(m64p_error, C.c_int, C.c_int) FuncResizeWindow = C.CFUNCTYPE(m64p_error, C.c_int, C.c_int)
FuncGLGetDefaultFramebuffer = C.CFUNCTYPE(C.c_uint) FuncGLGetDefaultFramebuffer = C.CFUNCTYPE(C.c_uint32)
FuncInitWithRenderMode = C.CFUNCTYPE(m64p_error, C.c_int)
FuncVKGetSurface = C.CFUNCTYPE(m64p_error, C.POINTER(C.c_void_p), C.c_void_p)
FuncVKGetInstanceExtensions = C.CFUNCTYPE(m64p_error, C.POINTER(C.c_char_p), C.POINTER(C.c_uint32))
class m64p_video_extension_functions(C.Structure): class M64pVideoExtensionFunctions(C.Structure):
_fields_ = [ _fields_ = [
('Functions', C.c_uint), ('Functions', C.c_uint),
('VidExtFuncInit', FuncInit), ('VidExtFuncInit', FuncInit),
('VidExtFuncQuit', FuncQuit), ('VidExtFuncQuit', FuncQuit),
('VidExtFuncListModes', FuncListModes), ('VidExtFuncListModes', FuncListModes),
('VidExtFuncListRates', FuncListRates),
('VidExtFuncSetMode', FuncSetMode), ('VidExtFuncSetMode', FuncSetMode),
('VidExtFuncSetModeWithRate', FuncSetModeWithRate),
('VidExtFuncGLGetProc', FuncGLGetProc), ('VidExtFuncGLGetProc', FuncGLGetProc),
('VidExtFuncGLSetAttr', FuncGLSetAttr), ('VidExtFuncGLSetAttr', FuncGLSetAttr),
('VidExtFuncGLGetAttr', FuncGLGetAttr), ('VidExtFuncGLGetAttr', FuncGLGetAttr),
@ -241,12 +270,8 @@ class m64p_video_extension_functions(C.Structure):
('VidExtFuncSetCaption', FuncSetCaption), ('VidExtFuncSetCaption', FuncSetCaption),
('VidExtFuncToggleFS', FuncToggleFS), ('VidExtFuncToggleFS', FuncToggleFS),
('VidExtFuncResizeWindow', FuncResizeWindow), ('VidExtFuncResizeWindow', FuncResizeWindow),
('VidExtFuncGLGetDefaultFramebuffer', FuncGLGetDefaultFramebuffer) ('VidExtFuncGLGetDefaultFramebuffer', FuncGLGetDefaultFramebuffer),
('VidExtFuncInitWithRenderMode', FuncInitWithRenderMode),
('VidExtFuncVKGetSurface', FuncVKGetSurface),
('VidExtFuncVKGetInstanceExtensions', FuncVKGetInstanceExtensions)
] ]
LOGO = " __ __ __ _ _ ____ _ \n"
LOGO += "| \/ |_ _ _ __ ___ _ __ / /_ | || | | _ \| |_ _ ___ \n"
LOGO += "| |\/| | | | | '_ \ / _ \ '_ \| '_ \| || |_| |_) | | | | / __| \n"
LOGO += "| | | | |_| | |_) | __/ | | | (_) |__ _| __/| | |_| \__ \ \n"
LOGO += "|_| |_|\__,_| .__/ \___|_| |_|\___/ |_| |_| |_|\__,_|___/ \n"
LOGO += " |_| \n"

View file

@ -20,10 +20,11 @@ try:
# nvidia hack # nvidia hack
from OpenGL import GL from OpenGL import GL
glimport = True glimport = True
except: except ModuleNotFoundError:
glimport = False glimport = False
from PyQt5.QtOpenGL import QGLFormat from PyQt5.QtOpenGL import QGLFormat
from PyQt5.QtWidgets import QApplication
from sdl2 import SDL_WasInit, SDL_InitSubSystem, SDL_QuitSubSystem, SDL_INIT_VIDEO from sdl2 import SDL_WasInit, SDL_InitSubSystem, SDL_QuitSubSystem, SDL_INIT_VIDEO
from sdl2 import SDL_GetNumDisplayModes, SDL_DisplayMode, SDL_GetDisplayMode from sdl2 import SDL_GetNumDisplayModes, SDL_DisplayMode, SDL_GetDisplayMode
@ -35,18 +36,20 @@ try:
if not SDL_WasInit(SDL_INIT_VIDEO): if not SDL_WasInit(SDL_INIT_VIDEO):
SDL_InitSubSystem(SDL_INIT_VIDEO) SDL_InitSubSystem(SDL_INIT_VIDEO)
MODES = [] MODES = []
RATES = []
display = SDL_DisplayMode() display = SDL_DisplayMode()
for mode in range(SDL_GetNumDisplayModes(0)): for m in range(SDL_GetNumDisplayModes(0)):
ret = SDL_GetDisplayMode(0, mode, ctypes.byref(display)) ret = SDL_GetDisplayMode(0, m, ctypes.byref(display))
if (display.w, display.h) not in MODES: if (display.w, display.h) not in MODES:
MODES.append((display.w, display.h)) MODES.append((display.w, display.h))
RATES.append(display.refresh_rate)
if SDL_WasInit(SDL_INIT_VIDEO): if SDL_WasInit(SDL_INIT_VIDEO):
SDL_QuitSubSystem(SDL_INIT_VIDEO) SDL_QuitSubSystem(SDL_INIT_VIDEO)
except Exception as err: except Exception as err:
log.warn(str(err)) log.warn(str(err))
class Video(): class Video:
"""Mupen64Plus video extension""" """Mupen64Plus video extension"""
def __init__(self): def __init__(self):
@ -58,10 +61,10 @@ class Video():
self.major = None self.major = None
self.minor = None self.minor = None
def set_widget(self, parent): def set_widget(self, parent, widget):
"""Sets GL widget.""" """Sets GL widget."""
self.parent = parent self.parent = parent
self.widget = self.parent.glwidget self.widget = widget
def init(self): def init(self):
"""Initialize GL context.""" """Initialize GL context."""
@ -70,16 +73,18 @@ class Video():
self.glcontext = self.widget.context() self.glcontext = self.widget.context()
self.glcontext.setFormat(self.glformat) self.glcontext.setFormat(self.glformat)
self.glcontext.create() self.glcontext.create()
self.parent.vidext_init.emit(self.glcontext)
return M64ERR_SUCCESS return M64ERR_SUCCESS
def quit(self): def quit(self):
"""Shuts down the video system.""" """Shuts down the video system."""
if self.glcontext: if self.glcontext:
self.glcontext.doneCurrent() self.glcontext.doneCurrent()
self.glcontext.moveToThread(QApplication.instance().thread())
self.glcontext = None self.glcontext = None
return M64ERR_SUCCESS return M64ERR_SUCCESS
def list_fullscreen_modes(self, size_array, num_sizes): def list_modes(self, size_array, num_sizes):
"""Enumerates the available resolutions """Enumerates the available resolutions
for fullscreen video modes.""" for fullscreen video modes."""
num_sizes.contents.value = len(MODES) num_sizes.contents.value = len(MODES)
@ -89,19 +94,31 @@ class Video():
size_array[num].uiHeight = height size_array[num].uiHeight = height
return M64ERR_SUCCESS return M64ERR_SUCCESS
def set_video_mode(self, width, height, bits, mode): def list_rates(self, size_array, num_rates, rates):
"""Enumerates the available rates
for fullscreen video modes."""
num_rates.contents.value = len(RATES)
for num, rate in enumerate(RATES):
rates[num] = rate
return M64ERR_SUCCESS
def set_mode(self, width, height, bits, mode, flags):
"""Creates a rendering window.""" """Creates a rendering window."""
self.glcontext.makeCurrent() self.widget.makeCurrent()
if self.glcontext.isValid(): if self.widget.isValid():
if glimport: if glimport:
GL.glClearColor(0.0, 0.0, 0.0, 1.0); GL.glClearColor(0.0, 0.0, 0.0, 1.0)
GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
self.widget.swapBuffers() self.widget.swapBuffers()
GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT); GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
return M64ERR_SUCCESS return M64ERR_SUCCESS
else: else:
return M64ERR_SYSTEM_FAIL return M64ERR_SYSTEM_FAIL
def set_mode_with_rate(self, width, height, rate, bits, mode, flags):
"""Creates a rendering window."""
return self.set_mode(width, height, bits, mode, flags)
def set_caption(self, title): def set_caption(self, title):
"""Sets the caption text of the """Sets the caption text of the
emulator rendering window. """ emulator rendering window. """
@ -112,7 +129,7 @@ class Video():
def toggle_fs(self): def toggle_fs(self):
"""Toggles between fullscreen and """Toggles between fullscreen and
windowed rendering modes. """ windowed rendering modes. """
self.widget.toggle_fs.emit() self.parent.toggle_fs.emit()
return M64ERR_SUCCESS return M64ERR_SUCCESS
def gl_get_proc(self, proc): def gl_get_proc(self, proc):
@ -128,8 +145,8 @@ class Video():
"""Sets OpenGL attributes.""" """Sets OpenGL attributes."""
attr_map = { attr_map = {
M64P_GL_DOUBLEBUFFER: self.glformat.setDoubleBuffer, M64P_GL_DOUBLEBUFFER: self.glformat.setDoubleBuffer,
M64P_GL_BUFFER_SIZE: self.glformat.setDepthBufferSize, M64P_GL_BUFFER_SIZE: None,
M64P_GL_DEPTH_SIZE: self.glformat.setDepth, M64P_GL_DEPTH_SIZE: self.glformat.setDepthBufferSize,
M64P_GL_RED_SIZE: self.glformat.setRedBufferSize, M64P_GL_RED_SIZE: self.glformat.setRedBufferSize,
M64P_GL_GREEN_SIZE: self.glformat.setGreenBufferSize, M64P_GL_GREEN_SIZE: self.glformat.setGreenBufferSize,
M64P_GL_BLUE_SIZE: self.glformat.setBlueBufferSize, M64P_GL_BLUE_SIZE: self.glformat.setBlueBufferSize,
@ -139,21 +156,25 @@ class Video():
M64P_GL_MULTISAMPLESAMPLES: self.glformat.setSamples, M64P_GL_MULTISAMPLESAMPLES: self.glformat.setSamples,
M64P_GL_CONTEXT_MAJOR_VERSION: self.set_major, M64P_GL_CONTEXT_MAJOR_VERSION: self.set_major,
M64P_GL_CONTEXT_MINOR_VERSION: self.set_minor, M64P_GL_CONTEXT_MINOR_VERSION: self.set_minor,
M64P_GL_CONTEXT_PROFILE_MASK: self.glformat.setProfile M64P_GL_CONTEXT_PROFILE_MASK: self.set_profile
} }
set_attr = attr_map[attr] set_attr = attr_map[attr]
set_attr(value) if set_attr:
set_attr(value)
if attr == M64P_GL_CONTEXT_MAJOR_VERSION or attr == M64P_GL_CONTEXT_MINOR_VERSION: if attr == M64P_GL_CONTEXT_MAJOR_VERSION or attr == M64P_GL_CONTEXT_MINOR_VERSION:
if self.major and self.minor: if self.major and self.minor:
self.glformat.setVersion(self.major, self.minor) self.glformat.setVersion(self.major, self.minor)
return M64ERR_SUCCESS return M64ERR_SUCCESS
def gl_get_attr(self, attr, value): def gl_get_attr(self, attr, value):
"""Gets OpenGL attributes.""" """Gets OpenGL attributes."""
attr_map = { attr_map = {
M64P_GL_DOUBLEBUFFER: self.glformat.doubleBuffer, M64P_GL_DOUBLEBUFFER: self.glformat.doubleBuffer,
M64P_GL_BUFFER_SIZE: self.glformat.depthBufferSize, M64P_GL_BUFFER_SIZE: None,
M64P_GL_DEPTH_SIZE: self.glformat.depth, M64P_GL_DEPTH_SIZE: self.glformat.depthBufferSize,
M64P_GL_RED_SIZE: self.glformat.redBufferSize, M64P_GL_RED_SIZE: self.glformat.redBufferSize,
M64P_GL_GREEN_SIZE: self.glformat.greenBufferSize, M64P_GL_GREEN_SIZE: self.glformat.greenBufferSize,
M64P_GL_BLUE_SIZE: self.glformat.blueBufferSize, M64P_GL_BLUE_SIZE: self.glformat.blueBufferSize,
@ -163,19 +184,23 @@ class Video():
M64P_GL_MULTISAMPLESAMPLES: self.glformat.samples, M64P_GL_MULTISAMPLESAMPLES: self.glformat.samples,
M64P_GL_CONTEXT_MAJOR_VERSION: self.glformat.majorVersion, M64P_GL_CONTEXT_MAJOR_VERSION: self.glformat.majorVersion,
M64P_GL_CONTEXT_MINOR_VERSION: self.glformat.minorVersion, M64P_GL_CONTEXT_MINOR_VERSION: self.glformat.minorVersion,
M64P_GL_CONTEXT_PROFILE_MASK: self.glformat.profile M64P_GL_CONTEXT_PROFILE_MASK: self.get_profile
} }
get_attr = attr_map[attr] get_attr = attr_map[attr]
new_value = int(get_attr()) if get_attr:
if new_value == value.contents.value: new_value = int(get_attr())
return M64ERR_SUCCESS value.contents.value = new_value
else: if new_value != value.contents.value:
return M64ERR_SYSTEM_FAIL return M64ERR_SYSTEM_FAIL
return M64ERR_SUCCESS
def gl_swap_buf(self): def gl_swap_buf(self):
"""Swaps the front/back buffers after """Swaps the front/back buffers after
rendering an output video frame. """ rendering an output video frame. """
self.widget.swapBuffers() if self.widget.isValid():
self.widget.swapBuffers()
return M64ERR_SUCCESS return M64ERR_SUCCESS
def resize_window(self, width, height): def resize_window(self, width, height):
@ -187,19 +212,47 @@ class Video():
"""Gets default framebuffer.""" """Gets default framebuffer."""
return 0 return 0
def init_with_render_mode(self, mode):
return self.init()
def vk_get_surface(self, a, b):
return M64ERR_SUCCESS
def vk_get_instance_extensions(self, a, b):
return M64ERR_SUCCESS
def set_major(self, major): def set_major(self, major):
self.major = major self.major = major
def set_minor(self, minor): def set_minor(self, minor):
self.minor = minor self.minor = minor
def set_profile(self, value):
if value == M64P_GL_CONTEXT_PROFILE_CORE:
self.glformat.setProfile(QGLFormat.CoreProfile)
elif value == M64P_GL_CONTEXT_PROFILE_COMPATIBILITY:
self.glformat.setProfile(QGLFormat.CompatibilityProfile)
else:
self.glformat.setProfile(QGLFormat.CompatibilityProfile)
def get_profile(self):
profile = self.glformat.profile()
if profile == QGLFormat.CoreProfile:
return M64P_GL_CONTEXT_PROFILE_CORE
elif profile == QGLFormat.CompatibilityProfile:
return M64P_GL_CONTEXT_PROFILE_COMPATIBILITY
else:
return M64P_GL_CONTEXT_PROFILE_COMPATIBILITY
video = Video() video = Video()
vidext = m64p_video_extension_functions() vidext = M64pVideoExtensionFunctions()
vidext.Functions = 12 vidext.Functions = 17
vidext.VidExtFuncInit = FuncInit(video.init) vidext.VidExtFuncInit = FuncInit(video.init)
vidext.VidExtFuncQuit = FuncQuit(video.quit) vidext.VidExtFuncQuit = FuncQuit(video.quit)
vidext.VidExtFuncListModes = FuncListModes(video.list_fullscreen_modes) vidext.VidExtFuncListModes = FuncListModes(video.list_modes)
vidext.VidExtFuncSetMode = FuncSetMode(video.set_video_mode) vidext.VidExtFuncListRates = FuncListRates(video.list_rates)
vidext.VidExtFuncSetMode = FuncSetMode(video.set_mode)
vidext.VidExtFuncSetModeWithRate = FuncSetModeWithRate(video.set_mode_with_rate)
vidext.VidExtFuncGLGetProc = FuncGLGetProc(video.gl_get_proc) vidext.VidExtFuncGLGetProc = FuncGLGetProc(video.gl_get_proc)
vidext.VidExtFuncGLSetAttr = FuncGLSetAttr(video.gl_set_attr) vidext.VidExtFuncGLSetAttr = FuncGLSetAttr(video.gl_set_attr)
vidext.VidExtFuncGLGetAttr = FuncGLGetAttr(video.gl_get_attr) vidext.VidExtFuncGLGetAttr = FuncGLGetAttr(video.gl_get_attr)
@ -208,3 +261,6 @@ vidext.VidExtFuncSetCaption = FuncSetCaption(video.set_caption)
vidext.VidExtFuncToggleFS = FuncToggleFS(video.toggle_fs) vidext.VidExtFuncToggleFS = FuncToggleFS(video.toggle_fs)
vidext.VidExtFuncResizeWindow = FuncResizeWindow(video.resize_window) vidext.VidExtFuncResizeWindow = FuncResizeWindow(video.resize_window)
vidext.VidExtFuncGLGetDefaultFramebuffer = FuncGLGetDefaultFramebuffer(video.gl_get_default_framebuffer) vidext.VidExtFuncGLGetDefaultFramebuffer = FuncGLGetDefaultFramebuffer(video.gl_get_default_framebuffer)
vidext.VidExtFuncInitWithRenderMode = FuncInitWithRenderMode(video.init_with_render_mode)
vidext.VidExtFuncVKGetSurface = FuncVKGetSurface(video.vk_get_surface)
vidext.VidExtFuncVKGetInstanceExtensions = FuncVKGetInstanceExtensions(video.vk_get_instance_extensions)

View file

@ -18,7 +18,7 @@ import os
import re import re
from collections import defaultdict from collections import defaultdict
from PyQt5.QtWidgets import QDialog, QTreeWidgetItem, QListWidgetItem from PyQt5.QtWidgets import QDialog, QTreeWidgetItem, QListWidgetItem, QTreeWidgetItemIterator
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from m64py.core.defs import * from m64py.core.defs import *
@ -127,7 +127,7 @@ class Cheat(QDialog, Ui_CheatDialog):
name = "%s\\%s" % (parent.text(column), name) name = "%s\\%s" % (parent.text(column), name)
data = item.data(column, Qt.UserRole) data = item.data(column, Qt.UserRole)
if state == Qt.Checked: if state == Qt.Checked:
codes_type = m64p_cheat_code * len(data) codes_type = M64pCheatCode * len(data)
codes = codes_type() codes = codes_type()
for num, cheat in enumerate(data): for num, cheat in enumerate(data):
cd, address, value, choices = cheat cd, address, value, choices = cheat

View file

@ -14,26 +14,17 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
from PyQt5.QtCore import Qt, pyqtSignal, QMargins from PyQt5.QtCore import Qt, QMargins
from PyQt5.QtOpenGL import QGLWidget from PyQt5.QtOpenGL import QGLWidget
from m64py.core.defs import *
from m64py.frontend.keymap import QT2SDL2
class GLWidget(QGLWidget): class GLWidget(QGLWidget):
toggle_fs = pyqtSignal() def __init__(self, parent=None):
def __init__(self, parent):
QGLWidget.__init__(self, parent) QGLWidget.__init__(self, parent)
self.parent = parent
self.worker = parent.worker
self.setAttribute(Qt.WA_NativeWindow, True) self.setAttribute(Qt.WA_NativeWindow, True)
self.setContentsMargins(QMargins()) self.setContentsMargins(QMargins())
self.setFocusPolicy(Qt.StrongFocus) self.setFocusPolicy(Qt.StrongFocus)
self.setFocus(True)
self.toggle_fs.connect(self.toggle_fullscreen)
def showEvent(self, event): def showEvent(self, event):
self.setFocus(True) self.setFocus(True)
@ -44,43 +35,3 @@ class GLWidget(QGLWidget):
def paintEvent(self, event): def paintEvent(self, event):
pass pass
def mouseDoubleClickEvent(self, event):
self.toggle_fs.emit()
def keyPressEvent(self, event):
if self.worker.state == M64EMU_RUNNING:
key = event.key()
modifiers = event.modifiers()
if modifiers & Qt.AltModifier and \
(key == Qt.Key_Enter or key == Qt.Key_Return):
self.toggle_fs.emit()
elif key == Qt.Key_F3:
self.worker.save_title()
elif key == Qt.Key_F4:
self.worker.save_snapshot()
else:
try:
sdl_key = QT2SDL2[key]
self.worker.send_sdl_keydown(sdl_key)
except KeyError:
pass
def keyReleaseEvent(self, event):
if self.worker.state == M64EMU_RUNNING:
key = event.key()
try:
sdl_key = QT2SDL2[key]
self.worker.send_sdl_keyup(sdl_key)
except KeyError:
pass
def toggle_fullscreen(self):
window = self.window()
if window.isFullScreen():
self.parent.menubar.show()
self.parent.statusbar.show()
else:
self.parent.menubar.hide()
self.parent.statusbar.hide()
window.setWindowState(window.windowState() ^ Qt.WindowFullScreen)

View file

@ -18,9 +18,9 @@ from PyQt5.QtCore import Qt
from m64py.frontend.keycodes import * from m64py.frontend.keycodes import *
QT2SDL2 = {} QT2SDL2 = dict()
SCANCODE2KEYCODE = {} SCANCODE2KEYCODE = dict()
KEYCODE2SCANCODE = {} KEYCODE2SCANCODE = dict()
QT2SDL2[Qt.Key_A] = SDL_SCANCODE_A QT2SDL2[Qt.Key_A] = SDL_SCANCODE_A
QT2SDL2[Qt.Key_B] = SDL_SCANCODE_B QT2SDL2[Qt.Key_B] = SDL_SCANCODE_B

View file

@ -35,6 +35,10 @@ class Log:
if self.logview: if self.logview:
self.logview.msg_written.emit(msg) self.logview.msg_written.emit(msg)
def flush(self):
if self.out:
self.out.flush()
class LogView(QDialog, Ui_LogView): class LogView(QDialog, Ui_LogView):
msg_written = pyqtSignal(str) msg_written = pyqtSignal(str)

View file

@ -17,10 +17,11 @@
import os import os
import sys import sys
from PyQt5.QtOpenGL import QGLContext
from PyQt5.QtGui import QKeySequence, QPixmap from PyQt5.QtGui import QKeySequence, QPixmap
from PyQt5.QtWidgets import QApplication, QMainWindow, QGraphicsView, QGraphicsScene, QGraphicsPixmapItem from PyQt5.QtWidgets import QApplication, QMainWindow, QGraphicsView, QGraphicsScene, QGraphicsPixmapItem
from PyQt5.QtWidgets import QAction, QLabel, QFileDialog, QStackedWidget, QActionGroup, QSizePolicy from PyQt5.QtWidgets import QAction, QLabel, QFileDialog, QStackedWidget, QActionGroup, QSizePolicy, QDialog
from PyQt5.QtCore import Qt, QTimer, QFileInfo, QEvent, QMargins, pyqtSignal, pyqtSlot from PyQt5.QtCore import Qt, QTimer, QFileInfo, QEvent, QMargins, pyqtSignal, pyqtSlot, QThread
from m64py.core.defs import * from m64py.core.defs import *
from m64py.frontend.dialogs import * from m64py.frontend.dialogs import *
@ -34,6 +35,7 @@ from m64py.frontend.settings import Settings
from m64py.frontend.glwidget import GLWidget from m64py.frontend.glwidget import GLWidget
from m64py.ui.mainwindow_ui import Ui_MainWindow from m64py.ui.mainwindow_ui import Ui_MainWindow
from m64py.frontend.recentfiles import RecentFiles from m64py.frontend.recentfiles import RecentFiles
from m64py.frontend.keymap import QT2SDL2
class MainWindow(QMainWindow, Ui_MainWindow): class MainWindow(QMainWindow, Ui_MainWindow):
@ -48,6 +50,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
save_image = pyqtSignal(bool) save_image = pyqtSignal(bool)
info_dialog = pyqtSignal(str) info_dialog = pyqtSignal(str)
archive_dialog = pyqtSignal(list) archive_dialog = pyqtSignal(list)
vidext_init = pyqtSignal(QGLContext)
toggle_fs = pyqtSignal()
def __init__(self, optparse): def __init__(self, optparse):
"""Constructor""" """Constructor"""
@ -55,6 +59,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.setupUi(self) self.setupUi(self)
self.opts, self.args = optparse self.opts, self.args = optparse
self._initialize_attempt = 0
logview.setParent(self) logview.setParent(self)
logview.setWindowFlags(Qt.Dialog) logview.setWindowFlags(Qt.Dialog)
@ -71,7 +77,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
SIZE_3X: self.action3X} SIZE_3X: self.action3X}
self.slots = {} self.slots = {}
self.view = None
self.stack = None self.stack = None
self.glwidget = None self.glwidget = None
self.cheats = None self.cheats = None
@ -97,16 +102,14 @@ class MainWindow(QMainWindow, Ui_MainWindow):
if event.type() == QEvent.WindowStateChange: if event.type() == QEvent.WindowStateChange:
if event.oldState() == Qt.WindowMaximized: if event.oldState() == Qt.WindowMaximized:
self.maximized = False self.maximized = False
elif event.oldState() == Qt.WindowNoState and \ elif event.oldState() == Qt.WindowNoState and self.windowState() == Qt.WindowMaximized:
self.windowState() == Qt.WindowMaximized:
self.maximized = True self.maximized = True
def resizeEvent(self, event): def resizeEvent(self, event):
event.ignore() event.ignore()
size = event.size() size = event.size()
width, height = size.width(), size.height()
if self.widgets_height: if self.widgets_height:
width, height = size.width(), size.height() - self.widgets_height width, height = size.width(), size.height()
self.window_size_triggered((width, height)) self.window_size_triggered((width, height))
else: else:
width, height = size.width(), size.height() width, height = size.width(), size.height()
@ -122,11 +125,40 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.create_size_actions() self.create_size_actions()
self.center_widget() self.center_widget()
def mouseDoubleClickEvent(self, event):
self.toggle_fs.emit()
def keyPressEvent(self, event):
if self.worker.state == M64EMU_RUNNING:
key = event.key()
modifiers = event.modifiers()
if modifiers & Qt.AltModifier and \
(key == Qt.Key_Enter or key == Qt.Key_Return):
self.toggle_fs.emit()
elif key == Qt.Key_F3:
self.worker.save_title()
elif key == Qt.Key_F4:
self.worker.save_snapshot()
else:
try:
sdl_key = QT2SDL2[key]
self.worker.send_sdl_keydown(sdl_key)
except KeyError:
pass
def keyReleaseEvent(self, event):
if self.worker.state == M64EMU_RUNNING:
key = event.key()
try:
sdl_key = QT2SDL2[key]
self.worker.send_sdl_keyup(sdl_key)
except KeyError:
pass
def window_size_triggered(self, size): def window_size_triggered(self, size):
window_width, window_height = size window_width, window_height = size
if self.vidext and self.worker.core.get_handle(): if self.vidext and self.worker.core.get_handle():
fullscreen = self.window().isFullScreen() game_height = window_height - self.widgets_height
game_height = window_height
game_width = window_width game_width = window_width
if not sys.platform == "win32": if not sys.platform == "win32":
@ -137,18 +169,15 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.worker.core.config.set_parameter("ScreenWidth", game_width) self.worker.core.config.set_parameter("ScreenWidth", game_width)
self.worker.core.config.set_parameter("ScreenHeight", game_height) self.worker.core.config.set_parameter("ScreenHeight", game_height)
if not fullscreen: video_size = (game_width << 16) + game_height
video_size = (game_width << 16) + game_height
else:
video_size = (game_width << 16) + (game_height + self.widgets_height)
if self.worker.state in (M64EMU_RUNNING, M64EMU_PAUSED): if self.worker.state in (M64EMU_RUNNING, M64EMU_PAUSED):
self.worker.core_state_set(M64CORE_VIDEO_SIZE, video_size) self.worker.core_state_set(M64CORE_VIDEO_SIZE, video_size)
self.glwidget.move(int((window_width - game_width) / 2), 0) self.glwidget.move(int((window_width - game_width) / 2), 0)
self.set_sizes((window_width, window_height)) self.set_sizes((window_width, window_height - self.widgets_height))
self.settings.qset.setValue("size", (window_width, window_height)) self.settings.qset.setValue("size", (window_width, window_height - self.widgets_height))
self.resize(window_width, window_height + self.widgets_height) self.resize(window_width, window_height)
def set_sizes(self, size): def set_sizes(self, size):
"""Sets 'Window Size' radio buttons on resize event.""" """Sets 'Window Size' radio buttons on resize event."""
@ -194,23 +223,25 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.save_image.connect(self.on_save_image) self.save_image.connect(self.on_save_image)
self.info_dialog.connect(self.on_info_dialog) self.info_dialog.connect(self.on_info_dialog)
self.archive_dialog.connect(self.on_archive_dialog) self.archive_dialog.connect(self.on_archive_dialog)
self.toggle_fs.connect(self.on_toggle_fs)
self.vidext_init.connect(self.on_vidext_init)
def create_widgets(self): def create_widgets(self):
"""Creates central widgets.""" """Creates central widgets."""
self.stack = QStackedWidget(self) self.stack = QStackedWidget(None)
palette = self.stack.palette() palette = self.stack.palette()
palette.setColor(self.stack.backgroundRole(), Qt.black) palette.setColor(self.stack.backgroundRole(), Qt.black)
self.stack.setPalette(palette) self.stack.setPalette(palette)
self.stack.setAutoFillBackground(True) self.stack.setAutoFillBackground(True)
self.view = View(self)
self.glwidget = GLWidget(self) self.glwidget = GLWidget(self)
self.worker.video.set_widget(self)
self.worker.video.set_widget(self, self.glwidget)
self.setCentralWidget(self.stack) self.setCentralWidget(self.stack)
self.stack.addWidget(self.view)
self.stack.addWidget(View(self))
self.stack.addWidget(self.glwidget) self.stack.addWidget(self.glwidget)
self.stack.setCurrentWidget(self.view) self.stack.setCurrentIndex(0)
def create_state_slots(self): def create_state_slots(self):
"""Creates state slot actions.""" """Creates state slot actions."""
@ -241,6 +272,18 @@ class MainWindow(QMainWindow, Ui_MainWindow):
action.setToolTip("%sx%s" % (width, height)) action.setToolTip("%sx%s" % (width, height))
action.triggered.connect(lambda t, wi=w, he=h: self.resize(wi, he)) action.triggered.connect(lambda t, wi=w, he=h: self.resize(wi, he))
def on_vidext_init(self, context):
context.moveToThread(self.worker)
def on_toggle_fs(self):
if self.isFullScreen():
self.menubar.show()
self.statusbar.show()
else:
self.menubar.hide()
self.statusbar.hide()
self.setWindowState(self.windowState() ^ Qt.WindowFullScreen)
def on_file_open(self, filepath=None, filename=None): def on_file_open(self, filepath=None, filename=None):
"""Opens ROM file.""" """Opens ROM file."""
if not filepath: if not filepath:
@ -325,19 +368,17 @@ class MainWindow(QMainWindow, Ui_MainWindow):
def on_rom_opened(self): def on_rom_opened(self):
if self.vidext: if self.vidext:
self.stack.setCurrentWidget(self.glwidget) self.stack.setCurrentIndex(1)
self.glwidget.setFocus(True)
if not self.cheats: if not self.cheats:
self.cheats = Cheat(self) self.cheats = Cheat(self)
self.update_status(self.worker.core.rom_settings.goodname.decode()) self.update_status(self.worker.core.rom_settings.goodname.decode())
"""Use QTimer to wait for core initialization before toggling UI actions""" """Use QTimer to wait for core initialization before toggling UI actions"""
self._initialize_attempt = 0
QTimer.singleShot(1000, self.wait_for_initialize) QTimer.singleShot(1000, self.wait_for_initialize)
def on_rom_closed(self): def on_rom_closed(self):
if self.vidext and self.isFullScreen(): if self.vidext and self.isFullScreen():
self.glwidget.toggle_fs.emit() self.toggle_fs.emit()
self.stack.setCurrentWidget(self.view) self.stack.setCurrentIndex(0)
self.actionMute.setChecked(False) self.actionMute.setChecked(False)
self.actionPause.setChecked(False) self.actionPause.setChecked(False)
self.actionLimitFPS.setChecked(True) self.actionLimitFPS.setChecked(True)
@ -505,7 +546,6 @@ class MainWindow(QMainWindow, Ui_MainWindow):
class View(QGraphicsView): class View(QGraphicsView):
def __init__(self, parent=None): def __init__(self, parent=None):
QGraphicsView.__init__(self, parent) QGraphicsView.__init__(self, parent)
self.parent = parent
self.setContentsMargins(QMargins()) self.setContentsMargins(QMargins())
self.setStyleSheet("QGraphicsView {border:0px solid;margin:0px;}") self.setStyleSheet("QGraphicsView {border:0px solid;margin:0px;}")
self.setResizeAnchor(QGraphicsView.AnchorViewCenter) self.setResizeAnchor(QGraphicsView.AnchorViewCenter)

View file

@ -140,6 +140,7 @@ class Plugin(QDialog, Ui_PluginDialog):
def save_items(self): def save_items(self):
for param_name, item in self.widgets.items(): for param_name, item in self.widgets.items():
widget, widget_class, opts = item widget, widget_class, opts = item
param_value = None
if widget_class == QLineEdit: if widget_class == QLineEdit:
param_value = widget.text().encode() param_value = widget.text().encode()
elif widget_class == QSpinBox: elif widget_class == QSpinBox:

View file

@ -21,7 +21,7 @@ import fnmatch
from PyQt5.QtCore import QThread from PyQt5.QtCore import QThread
from m64py.utils import sl from m64py.utils import sl
from m64py.core.defs import m64p_rom_header from m64py.core.defs import M64pRomHeader
from m64py.frontend.log import log from m64py.frontend.log import log
from m64py.archive import Archive, EXT_FILTER from m64py.archive import Archive, EXT_FILTER
@ -55,7 +55,7 @@ class ROMReader(QThread):
return files return files
def get_rom_crc(self, archive, fname): def get_rom_crc(self, archive, fname):
rom_header = m64p_rom_header() rom_header = M64pRomHeader()
ctypes.memmove( ctypes.memmove(
ctypes.byref(rom_header), ctypes.byref(rom_header),
archive.read(fname, ctypes.sizeof(rom_header)), archive.read(fname, ctypes.sizeof(rom_header)),

View file

@ -105,7 +105,6 @@ class Worker(QThread):
self.core.core_startup( self.core.core_startup(
str(self.library_path), self.parent.vidext) str(self.library_path), self.parent.vidext)
def core_shutdown(self): def core_shutdown(self):
"""Shutdowns core library.""" """Shutdowns core library."""
if self.core.get_handle(): if self.core.get_handle():
@ -335,6 +334,7 @@ class Worker(QThread):
"""Toggles actions state.""" """Toggles actions state."""
self.state = self.core_state_query(M64CORE_EMU_STATE) self.state = self.core_state_query(M64CORE_EMU_STATE)
cheat = bool(self.parent.cheats.cheats) if self.parent.cheats else False cheat = bool(self.parent.cheats.cheats) if self.parent.cheats else False
(load, pause, action, cheats) = True, False, False, False
if self.state == M64EMU_STOPPED: if self.state == M64EMU_STOPPED:
(load, pause, action, cheats) = True, False, False, False (load, pause, action, cheats) = True, False, False, False
elif self.state == M64EMU_PAUSED: elif self.state == M64EMU_PAUSED:

View file

@ -18,8 +18,8 @@ import re
def which(prog): def which(prog):
def is_exe(fpath): def is_exe(fp):
return os.path.exists(fpath) and os.access(fpath, os.X_OK) return os.path.exists(fp) and os.access(fp, os.X_OK)
fpath, fname = os.path.split(prog) fpath, fname = os.path.split(prog)
if fpath: if fpath:
if is_exe(prog): if is_exe(prog):
@ -36,7 +36,7 @@ def version_split(ver):
return "%d.%d.%d" % ( return "%d.%d.%d" % (
((ver >> 16) & 0xffff), ((ver >> 16) & 0xffff),
((ver >> 8) & 0xff), ((ver >> 8) & 0xff),
((ver & 0xff))) (ver & 0xff))
def sl(mot): def sl(mot):
@ -71,7 +71,7 @@ def format_options(param_help):
if not param_help: if not param_help:
return None return None
items = re.findall( items = re.findall(
"(\d+|[\d,-]+)\s?=\s?([\w/ %-]+)", param_help) r"(\d+|[\d,-]+)\s?=\s?([\w/ %-]+)", param_help)
for item in items: for item in items:
key, value = item key, value = item
if '-' in key[1:] or ',' in key: if '-' in key[1:] or ',' in key: