Annotation of previous/python-ui/hatari.py, revision 1.1

1.1     ! root        1: #!/usr/bin/env python
        !             2: #
        !             3: # Classes for Hatari emulator instance and mapping its congfiguration
        !             4: # variables with its command line option.
        !             5: #
        !             6: # Copyright (C) 2008-2010 by Eero Tamminen <eerot at berlios>
        !             7: #
        !             8: # This program is free software; you can redistribute it and/or modify
        !             9: # it under the terms of the GNU General Public License as published by
        !            10: # the Free Software Foundation; either version 2 of the License, or
        !            11: # (at your option) any later version.
        !            12: #
        !            13: # This program is distributed in the hope that it will be useful,
        !            14: # but WITHOUT ANY WARRANTY; without even the implied warranty of
        !            15: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        !            16: # GNU General Public License for more details.
        !            17: 
        !            18: import os
        !            19: import sys
        !            20: import time
        !            21: import signal
        !            22: import socket
        !            23: import select
        !            24: from config import ConfigStore
        !            25: 
        !            26: 
        !            27: # Running Hatari instance
        !            28: class Hatari:
        !            29:     "running hatari instance and methods for communicating with it"
        !            30:     basepath = "/tmp/hatari-ui-" + str(os.getpid())
        !            31:     logpath = basepath + ".log"
        !            32:     tracepath = basepath + ".trace"
        !            33:     debugpath = basepath + ".debug"
        !            34:     controlpath = basepath + ".socket"
        !            35:     server = None # singleton due to path being currently one per user
        !            36: 
        !            37:     def __init__(self, hataribin = None):
        !            38:         # collect hatari process zombies without waitpid()
        !            39:         signal.signal(signal.SIGCHLD, signal.SIG_IGN)
        !            40:         if hataribin:
        !            41:             self.hataribin = hataribin
        !            42:         else:
        !            43:             self.hataribin = "hatari"
        !            44:         self._create_server()
        !            45:         self.control = None
        !            46:         self.paused = False
        !            47:         self.pid = 0
        !            48: 
        !            49:     def is_compatible(self):
        !            50:         "check Hatari compatibility and return error string if it's not"
        !            51:         for line in os.popen(self.hataribin + " -h").readlines():
        !            52:             if line.find("--control-socket") >= 0:
        !            53:                 return None
        !            54:         return "Hatari not found or it doesn't support the required --control-socket option!"
        !            55: 
        !            56:     def save_config(self):
        !            57:         os.popen(self.hataribin + " --saveconfig")
        !            58: 
        !            59:     def _create_server(self):
        !            60:         if self.server:
        !            61:             return
        !            62:         self.server = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        !            63:         if os.path.exists(self.controlpath):
        !            64:             os.unlink(self.controlpath)
        !            65:         self.server.bind(self.controlpath)
        !            66:         self.server.listen(1)
        !            67:         
        !            68:     def _send_message(self, msg):
        !            69:         if self.control:
        !            70:             self.control.send(msg)
        !            71:             return True
        !            72:         else:
        !            73:             print "ERROR: no Hatari (control socket)"
        !            74:             return False
        !            75:         
        !            76:     def change_option(self, option):
        !            77:         "change_option(option), changes given Hatari cli option"
        !            78:         return self._send_message("hatari-option %s\n" % option)
        !            79:         
        !            80:     def set_path(self, key, path):
        !            81:         "set_path(key, path), sets path with given key"
        !            82:         return self._send_message("hatari-path %s %s\n" % (key, path))
        !            83: 
        !            84:     def set_device(self, device, enabled):
        !            85:         # needed because CLI options cannot disable devices, only enable
        !            86:         "set_path(device, enabled), sets whether given device is enabled or not"
        !            87:         if enabled:
        !            88:             return self._send_message("hatari-enable %s\n" % device)
        !            89:         else:
        !            90:             return self._send_message("hatari-disable %s\n" % device)
        !            91:         
        !            92:     def trigger_shortcut(self, shortcut):
        !            93:         "trigger_shortcut(shortcut), triggers given Hatari (keyboard) shortcut"
        !            94:         return self._send_message("hatari-shortcut %s\n" % shortcut)
        !            95: 
        !            96:     def insert_event(self, event):
        !            97:         "insert_event(event), synthetizes given key/mouse Atari event"
        !            98:         return self._send_message("hatari-event %s\n" % event)
        !            99: 
        !           100:     def debug_command(self, cmd):
        !           101:         "debug_command(command), runs given Hatari debugger command"
        !           102:         return self._send_message("hatari-debug %s\n" % cmd)
        !           103: 
        !           104:     def pause(self):
        !           105:         "pause(), pauses Hatari emulation"
        !           106:         return self._send_message("hatari-stop\n")
        !           107: 
        !           108:     def unpause(self):
        !           109:         "unpause(), continues Hatari emulation"
        !           110:         return self._send_message("hatari-cont\n")
        !           111:     
        !           112:     def _open_output_file(self, hataricommand, option, path):
        !           113:         if os.path.exists(path):
        !           114:             os.unlink(path)
        !           115:         # TODO: why fifo doesn't work properly (blocks forever on read or
        !           116:         #       reads only byte at the time and stops after first newline)?
        !           117:         #os.mkfifo(path)
        !           118:         #raw_input("attach strace now, then press Enter\n")
        !           119:         
        !           120:         # ask Hatari to open/create the requested output file...
        !           121:         hataricommand("%s %s" % (option, path))
        !           122:         wait = 0.025
        !           123:         # ...and wait for it to appear before returning it
        !           124:         for i in range(0, 8):
        !           125:             time.sleep(wait)
        !           126:             if os.path.exists(path):
        !           127:                 return open(path, "r")
        !           128:             wait += wait
        !           129:         return None
        !           130: 
        !           131:     def open_debug_output(self):
        !           132:         "open_debug_output() -> file, opens Hatari debugger output file"
        !           133:         return self._open_output_file(self.debug_command, "f", self.debugpath)
        !           134: 
        !           135:     def open_trace_output(self):
        !           136:         "open_trace_output() -> file, opens Hatari tracing output file"
        !           137:         return self._open_output_file(self.change_option, "--trace-file", self.tracepath)
        !           138: 
        !           139:     def open_log_output(self):
        !           140:         "open_trace_output() -> file, opens Hatari debug log file"
        !           141:         return self._open_output_file(self.change_option, "--log-file", self.logpath)
        !           142:     
        !           143:     def get_lines(self, fileobj):
        !           144:         "get_lines(file) -> list of lines readable from given Hatari output file"
        !           145:         # wait until data is available, then wait for some more
        !           146:         # and only then the data can be read, otherwise its old
        !           147:         print "Request&wait data from Hatari..."
        !           148:         select.select([fileobj], [], [])
        !           149:         time.sleep(0.1)
        !           150:         print "...read the data lines"
        !           151:         lines = fileobj.readlines()
        !           152:         print "".join(lines)
        !           153:         return lines
        !           154: 
        !           155:     def enable_embed_info(self):
        !           156:         "enable_embed_info(), request embedded Hatari window ID change information"
        !           157:         self._send_message("hatari-embed-info\n")
        !           158: 
        !           159:     def get_embed_info(self):
        !           160:         "get_embed_info() -> (width, height), get embedded Hatari window size"
        !           161:         width, height = self.control.recv(12).split("x")
        !           162:         return (int(width), int(height))
        !           163: 
        !           164:     def get_control_socket(self):
        !           165:         "get_control_socket() -> socket which can be checked for embed ID changes"
        !           166:         return self.control
        !           167:         
        !           168:     def is_running(self):
        !           169:         "is_running() -> bool, True if Hatari is running, False otherwise"
        !           170:         if not self.pid:
        !           171:             return False
        !           172:         try:
        !           173:             os.waitpid(self.pid, os.WNOHANG)
        !           174:         except OSError, value:
        !           175:             print "Hatari PID %d had exited in the meanwhile:\n\t%s" % (self.pid, value)
        !           176:             self.pid = 0
        !           177:             return False
        !           178:         return True
        !           179:     
        !           180:     def run(self, extra_args = None, parent_win = None):
        !           181:         "run([parent window][,embedding args]), runs Hatari"
        !           182:         # if parent_win given, embed Hatari to it
        !           183:         pid = os.fork()
        !           184:         if pid < 0:
        !           185:             print "ERROR: fork()ing Hatari failed!"
        !           186:             return
        !           187:         if pid:
        !           188:             # in parent
        !           189:             self.pid = pid
        !           190:             if self.server:
        !           191:                 print "WAIT hatari to connect to control socket...",
        !           192:                 (self.control, addr) = self.server.accept()
        !           193:                 print "connected!"
        !           194:         else:
        !           195:             # child runs Hatari
        !           196:             env = os.environ
        !           197:             if parent_win:
        !           198:                 self._set_embed_env(env, parent_win)
        !           199:             # callers need to take care of confirming quitting
        !           200:             args = [self.hataribin, "--confirm-quit", "off"]
        !           201:             if self.server:
        !           202:                 args += ["--control-socket", self.controlpath]
        !           203:             if extra_args:
        !           204:                 args += extra_args
        !           205:             print "RUN:", args
        !           206:             os.execvpe(self.hataribin, args, env)
        !           207: 
        !           208:     def _set_embed_env(self, env, parent_win):
        !           209:         if sys.platform == 'win32':
        !           210:             win_id = parent_win.handle
        !           211:         else:
        !           212:             win_id = parent_win.xid
        !           213:         # tell SDL to use given widget's window
        !           214:         #env["SDL_WINDOWID"] = str(win_id)
        !           215: 
        !           216:         # above is broken: when SDL uses a window it hasn't created itself,
        !           217:         # it for some reason doesn't listen to any events delivered to that
        !           218:         # window nor implements XEMBED protocol to get them in a way most
        !           219:         # friendly to embedder:
        !           220:         #   http://standards.freedesktop.org/xembed-spec/latest/
        !           221:         #
        !           222:         # Instead we tell hatari to reparent itself after creating
        !           223:         # its own window into this program widget window
        !           224:         env["PARENT_WIN_ID"] = str(win_id)
        !           225: 
        !           226:     def kill(self):
        !           227:         "kill(), kill Hatari if it's running"
        !           228:         if self.pid:
        !           229:             os.kill(self.pid, signal.SIGKILL)
        !           230:             print "killed hatari with PID %d" % self.pid
        !           231:             self.pid = 0
        !           232:         if self.control:
        !           233:             self.control.close()
        !           234:             self.control = None
        !           235: 
        !           236: 
        !           237: # Mapping of requested values both to Hatari configuration
        !           238: # and command line options.
        !           239: #
        !           240: # By default this doesn't allow setting any other configuration
        !           241: # variables than the ones that were read from the configuration
        !           242: # file i.e. you get an exception if configuration variables
        !           243: # don't match to current Hatari.  So before using this the current
        !           244: # Hatari configuration should have been saved at least once.
        !           245: #
        !           246: # Because of some inconsistencies in the values (see e.g. sound),
        !           247: # this cannot just do these according to some mapping table, but
        !           248: # it needs actual method for (each) setting.
        !           249: class HatariConfigMapping(ConfigStore):
        !           250:     _paths = {
        !           251:         "memauto": ("[Memory]", "szAutoSaveFileName", "Automatic memory snapshot"),
        !           252:         "memsave": ("[Memory]", "szMemoryCaptureFileName", "Manual memory snapshot"),
        !           253:         "midiin":  ("[Midi]", "sMidiInFileName", "Midi input"),
        !           254:         "midiout": ("[Midi]", "sMidiOutFileName", "Midi output"),
        !           255:         "rs232in": ("[RS232]", "szInFileName", "RS232 I/O input"),
        !           256:         "rs232out": ("[RS232]", "szOutFileName", "RS232 I/O output"),
        !           257:         "printout": ("[Printer]", "szPrintToFileName", "Printer output"),
        !           258:         "soundout": ("[Sound]", "szYMCaptureFileName", "Sound output")
        !           259:     }
        !           260:     "access methods to Hatari configuration file variables and command line options"
        !           261:     def __init__(self, hatari):
        !           262:         userconfdir = ".hatari"
        !           263:         ConfigStore.__init__(self, userconfdir)
        !           264:         conffilename = "hatari.cfg"
        !           265:         self.load(self.get_filepath(conffilename))
        !           266: 
        !           267:         self._hatari = hatari
        !           268:         self._lock_updates = False
        !           269:         self._options = []
        !           270: 
        !           271:     def validate(self):
        !           272:         "exception is thrown if the loaded configuration isn't compatible"
        !           273:         for method in dir(self):
        !           274:             if '_' not in method:
        !           275:                 continue
        !           276:             # check class getters
        !           277:             starts = method[:method.find("_")]
        !           278:             if starts != "get":
        !           279:                 continue
        !           280:             # but ignore getters for other things than config
        !           281:             ends = method[method.rfind("_")+1:]
        !           282:             if ends in ("types", "names", "values", "changes", "checkpoint", "filepath"):
        !           283:                 continue
        !           284:             if ends in ("floppy", "joystick"):
        !           285:                 # use port '0' for checks
        !           286:                 getattr(self, method)(0)
        !           287:             else:
        !           288:                 getattr(self, method)()
        !           289: 
        !           290:     def _change_option(self, option):
        !           291:         if self._lock_updates:
        !           292:             self._options.append(option)
        !           293:         else:
        !           294:             self._hatari.change_option(option)
        !           295: 
        !           296:     def lock_updates(self):
        !           297:         "lock_updates(), collect Hatari configuration changes"
        !           298:         self._lock_updates = True
        !           299:     
        !           300:     def flush_updates(self):
        !           301:         "flush_updates(), apply collected Hatari configuration changes"
        !           302:         self._lock_updates = False
        !           303:         if not self._options:
        !           304:             return
        !           305:         self._hatari.change_option(" ".join(self._options))
        !           306:         self._options = []
        !           307: 
        !           308:     # ------------ paths ---------------
        !           309:     def get_paths(self):
        !           310:         paths = []
        !           311:         for key, item in self._paths.items():
        !           312:             paths.append((key, self.get(item[0], item[1]), item[2]))
        !           313:         return paths
        !           314:     
        !           315:     def set_paths(self, paths):
        !           316:         for key, path in paths:
        !           317:             self.set(self._paths[key][0], self._paths[key][1], path)
        !           318:             self._hatari.set_path(key, path)
        !           319: 
        !           320:     # ------------ midi ---------------
        !           321:     def get_midi(self):
        !           322:         return self.get("[Midi]", "bEnableMidi")
        !           323: 
        !           324:     def set_midi(self, value):
        !           325:         self.set("[Midi]", "bEnableMidi", value)
        !           326:         self._hatari.set_device("midi", value)
        !           327: 
        !           328:     # ------------ printer ---------------
        !           329:     def get_printer(self):
        !           330:         return self.get("[Printer]", "bEnablePrinting")
        !           331: 
        !           332:     def set_printer(self, value):
        !           333:         self.set("[Printer]", "bEnablePrinting", value)
        !           334:         self._hatari.set_device("printer", value)
        !           335: 
        !           336:     # ------------ RS232 ---------------
        !           337:     def get_rs232(self):
        !           338:         return self.get("[RS232]", "bEnableRS232")
        !           339: 
        !           340:     def set_rs232(self, value):
        !           341:         self.set("[RS232]", "bEnableRS232", value)
        !           342:         self._hatari.set_device("rs232", value)
        !           343: 
        !           344:     # ------------ machine ---------------
        !           345:     def get_machine_types(self):
        !           346:         return ("ST", "STE", "TT", "Falcon")
        !           347: 
        !           348:     def get_machine(self):
        !           349:         return self.get("[System]", "nMachineType")
        !           350: 
        !           351:     def set_machine(self, value):
        !           352:         self.set("[System]", "nMachineType", value)
        !           353:         self._change_option("--machine %s" % ("st", "ste", "tt", "falcon")[value])
        !           354: 
        !           355:     # ------------ CPU level ---------------
        !           356:     def get_cpulevel_types(self):
        !           357:         return ("68000", "68010", "68020", "68EC030+FPU", "68040")
        !           358: 
        !           359:     def get_cpulevel(self):
        !           360:         return self.get("[System]", "nCpuLevel")
        !           361: 
        !           362:     def set_cpulevel(self, value):
        !           363:         self.set("[System]", "nCpuLevel", value)
        !           364:         self._change_option("--cpulevel %d" % value)
        !           365: 
        !           366:     # ------------ CPU clock ---------------
        !           367:     def get_cpuclock_types(self):
        !           368:         return ("8 MHz", "16 MHz", "32 MHz") 
        !           369: 
        !           370:     def get_cpuclock(self):
        !           371:         clocks = {8:0, 16: 1, 32:2}
        !           372:         return clocks[self.get("[System]", "nCpuFreq")]
        !           373: 
        !           374:     def set_cpuclock(self, value):
        !           375:         clocks = [8, 16, 32]
        !           376:         if value < 0 or value > 2:
        !           377:             print "WARNING: CPU clock idx %d, clock fixed to 8 Mhz" % value
        !           378:             value = 8
        !           379:         else:
        !           380:             value = clocks[value]
        !           381:         self.set("[System]", "nCpuFreq", value)
        !           382:         self._change_option("--cpuclock %d" % value)
        !           383: 
        !           384:     # ------------ DSP type ---------------
        !           385:     def get_dsp_types(self):
        !           386:         return ("None", "Dummy", "Emulated")
        !           387: 
        !           388:     def get_dsp(self):
        !           389:         return self.get("[System]", "nDSPType")
        !           390: 
        !           391:     def set_dsp(self, value):
        !           392:         self.set("[System]", "nDSPType", value)
        !           393:         self._change_option("--dsp %s" % ("none", "dummy", "emu")[value])
        !           394: 
        !           395:     # ------------ compatible ---------------
        !           396:     def get_compatible(self):
        !           397:         return self.get("[System]", "bCompatibleCpu")
        !           398: 
        !           399:     def set_compatible(self, value):
        !           400:         self.set("[System]", "bCompatibleCpu", value)
        !           401:         self._change_option("--compatible %s" % str(value))
        !           402: 
        !           403:     # ------------ Timer-D ---------------
        !           404:     def get_timerd(self):
        !           405:         return self.get("[System]", "bPatchTimerD")
        !           406: 
        !           407:     def set_timerd(self, value):
        !           408:         self.set("[System]", "bPatchTimerD", value)
        !           409:         self._change_option("--timer-d %s" % str(value))
        !           410: 
        !           411:     # ------------ fastforward ---------------
        !           412:     def get_fastforward(self):
        !           413:         return self.get("[System]", "bFastForward")
        !           414: 
        !           415:     def set_fastforward(self, value):
        !           416:         self.set("[System]", "bFastForward", value)
        !           417:         self._change_option("--fast-forward %s" % str(value))
        !           418:         
        !           419:     # ------------ sound ---------------
        !           420:     def get_sound_values(self):
        !           421:         # 48kHz, 44.1kHz and STE/TT/Falcon DMA 50066Hz divisable values
        !           422:         return ("6000", "6258", "8000", "11025", "12000", "12517",
        !           423:                 "16000", "22050", "24000", "25033", "32000",
        !           424:                 "48000", "44100", "50066")
        !           425:     
        !           426:     def get_sound(self):
        !           427:         enabled = self.get("[Sound]", "bEnableSound")
        !           428:         hz = str(self.get("[Sound]", "nPlaybackFreq"))
        !           429:         return (enabled, hz)
        !           430: 
        !           431:     def set_sound(self, enabled, hz):
        !           432:         # map get_sound_values() index to Hatari config
        !           433:         try:
        !           434:             hz = int(hz)
        !           435:         except ValueError:
        !           436:             hz = 0
        !           437:         if hz < 6000 or hz > 50066:
        !           438:             hz = 44100
        !           439:         self.set("[Sound]", "nPlaybackFreq", hz)
        !           440:         self.set("[Sound]", "bEnableSound", enabled)
        !           441:         value = str(hz)
        !           442:         # and to cli option
        !           443:         if enabled:
        !           444:             self._change_option("--sound %s" % value)
        !           445:         else:
        !           446:             self._change_option("--sound off")
        !           447:         return value
        !           448:         
        !           449:         
        !           450:     # ----------- joystick --------------
        !           451:     def get_joystick_types(self):
        !           452:         return ("Disabled", "Real joystick", "Keyboard")
        !           453:     
        !           454:     def get_joystick_names(self):
        !           455:         return (
        !           456:         "ST Joystick 0",
        !           457:         "ST Joystick 1",
        !           458:         "STE Joypad A",
        !           459:         "STE Joypad B",
        !           460:         "Parport stick 1",
        !           461:         "Parport stick 2"
        !           462:         )
        !           463: 
        !           464:     def get_joystick(self, port):
        !           465:         # return index to get_joystick_values() array
        !           466:         return self.get("[Joystick%d]" % port, "nJoystickMode")
        !           467: 
        !           468:     def set_joystick(self, port, value):
        !           469:         # map get_sound_values() index to Hatari config
        !           470:         self.set("[Joystick%d]" % port, "nJoystickMode", value)
        !           471:         joytype = ("none", "real", "keys")[value]
        !           472:         self._change_option("--joy%d %s" % (port, joytype))
        !           473: 
        !           474:     # ------------ floppy image dir ---------------
        !           475:     def get_floppydir(self):
        !           476:         return self.get("[Floppy]", "szDiskImageDirectory")
        !           477:     
        !           478:     def set_floppydir(self, path):
        !           479:         return self.set("[Floppy]", "szDiskImageDirectory", path)
        !           480: 
        !           481:     # ------------ floppy disk images ---------------
        !           482:     def get_floppy(self, drive):
        !           483:         return self.get("[Floppy]", "szDisk%cFileName" % ("A", "B")[drive])
        !           484:     
        !           485:     def set_floppy(self, drive, filename):
        !           486:         self.set("[Floppy]", "szDisk%cFileName" %  ("A", "B")[drive], filename)
        !           487:         self._change_option("--disk-%c %s" % (("a", "b")[drive], filename))
        !           488: 
        !           489:     # ------------ slow FDC access ---------------
        !           490:     def get_slowfdc(self):
        !           491:         return self.get("[Floppy]", "bSlowFloppy")
        !           492: 
        !           493:     def set_slowfdc(self, value):
        !           494:         self.set("[Floppy]", "bSlowFloppy", value)
        !           495:         self._change_option("--slowfdc %s" % str(value))
        !           496: 
        !           497:     # ------------- disk protection -------------
        !           498:     def get_protection_types(self):
        !           499:         return ("Off", "On", "Auto")
        !           500: 
        !           501:     def get_floppy_protection(self):
        !           502:         return self.get("[Floppy]", "nWriteProtection")
        !           503: 
        !           504:     def get_hd_protection(self):
        !           505:         return self.get("[HardDisk]", "nWriteProtection")
        !           506: 
        !           507:     def set_floppy_protection(self, value):
        !           508:         self.set("[Floppy]", "nWriteProtection", value)
        !           509:         self._change_option("--protect-floppy %s" % self.get_protection_types()[value])
        !           510: 
        !           511:     def set_hd_protection(self, value):
        !           512:         self.set("[HardDisk]", "nWriteProtection", value)
        !           513:         self._change_option("--protect-hd %s" % self.get_protection_types()[value])
        !           514: 
        !           515:     # ------------ GEMDOS HD (dir) ---------------
        !           516:     def get_gemdos_dir(self):
        !           517:         self.get("[HardDisk]", "bUseHardDiskDirectory") # for validation
        !           518:         return self.get("[HardDisk]", "szHardDiskDirectory")
        !           519: 
        !           520:     def set_gemdos_dir(self, dirname):
        !           521:         if dirname and os.path.isdir(dirname):
        !           522:             self.set("[HardDisk]", "bUseHardDiskDirectory", True)
        !           523:         self.set("[HardDisk]", "szHardDiskDirectory", dirname)
        !           524:         self._change_option("--harddrive %s" % dirname)
        !           525: 
        !           526:     # ------------ ACSI HD (file) ---------------
        !           527:     def get_acsi_image(self):
        !           528:         self.get("[HardDisk]", "bUseHardDiskImage") # for validation
        !           529:         return self.get("[HardDisk]", "szHardDiskImage")
        !           530: 
        !           531:     def set_acsi_image(self, filename):
        !           532:         if filename and os.path.isfile(filename):
        !           533:             self.set("[HardDisk]", "bUseHardDiskImage", True)
        !           534:         self.set("[HardDisk]", "szHardDiskImage", filename)
        !           535:         self._change_option("--acsi %s" % filename)
        !           536: 
        !           537:     # ------------ IDE master (file) ---------------
        !           538:     def get_idemaster_image(self):
        !           539:         self.get("[HardDisk]", "bUseIdeMasterHardDiskImage") # for validation
        !           540:         return self.get("[HardDisk]", "szIdeMasterHardDiskImage")
        !           541: 
        !           542:     def set_idemaster_image(self, filename):
        !           543:         if filename and os.path.isfile(filename):
        !           544:             self.set("[HardDisk]", "bUseIdeMasterHardDiskImage", True)
        !           545:         self.set("[HardDisk]", "szIdeMasterHardDiskImage", filename)
        !           546:         self._change_option("--ide-master %s" % filename)
        !           547: 
        !           548:     # ------------ IDE slave (file) ---------------
        !           549:     def get_ideslave_image(self):
        !           550:         self.get("[HardDisk]", "bUseIdeSlaveHardDiskImage") # for validation
        !           551:         return self.get("[HardDisk]", "szIdeSlaveHardDiskImage")
        !           552: 
        !           553:     def set_ideslave_image(self, filename):
        !           554:         if filename and os.path.isfile(filename):
        !           555:             self.set("[HardDisk]", "bUseIdeSlaveHardDiskImage", True)
        !           556:         self.set("[HardDisk]", "szIdeSlaveHardDiskImage", filename)
        !           557:         self._change_option("--ide-slave %s" % filename)
        !           558: 
        !           559:     # ------------ TOS ROM ---------------
        !           560:     def get_tos(self):
        !           561:         return self.get("[ROM]", "szTosImageFileName")
        !           562:     
        !           563:     def set_tos(self, filename):
        !           564:         self.set("[ROM]", "szTosImageFileName", filename)
        !           565:         self._change_option("--tos %s" % filename)
        !           566: 
        !           567:     # ------------ memory ---------------
        !           568:     def get_memory_names(self):
        !           569:         # empty item in list shouldn't be shown, filter them out
        !           570:         return ("512kB", "1MB", "2MB", "4MB", "8MB", "14MB")
        !           571: 
        !           572:     def get_memory(self):
        !           573:         "return index to what get_memory_names() returns"
        !           574:         sizemap = (0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5)
        !           575:         memsize = self.get("[Memory]", "nMemorySize")
        !           576:         if memsize >= 0 and memsize < len(sizemap):
        !           577:             return sizemap[memsize]
        !           578:         return 1 # default = 1BM
        !           579: 
        !           580:     def set_memory(self, idx):
        !           581:         # map memory item index to memory size
        !           582:         sizemap = (0, 1, 2, 4, 8, 14)
        !           583:         if idx >= 0 and idx < len(sizemap):
        !           584:             memsize = sizemap[idx]
        !           585:         else:
        !           586:             memsize = 1
        !           587:         self.set("[Memory]", "nMemorySize", memsize)
        !           588:         self._change_option("--memsize %d" % memsize)
        !           589: 
        !           590:     # ------------ monitor ---------------
        !           591:     def get_monitor_types(self):
        !           592:         return ("Mono", "RGB", "VGA", "TV")
        !           593: 
        !           594:     def get_monitor(self):
        !           595:         return self.get("[Screen]", "nMonitorType")
        !           596: 
        !           597:     def set_monitor(self, value):
        !           598:         self.set("[Screen]", "nMonitorType", value)
        !           599:         self._change_option("--monitor %s" % ("mono", "rgb", "vga", "tv")[value])
        !           600: 
        !           601:     # ------------ frameskip ---------------
        !           602:     def get_frameskip_names(self):
        !           603:         return (
        !           604:             "Disabled",
        !           605:             "1 frame",
        !           606:             "2 frames",
        !           607:             "3 frames",
        !           608:             "4 frames",
        !           609:             "Automatic"
        !           610:         )
        !           611:     
        !           612:     def get_frameskip(self):
        !           613:         fs = self.get("[Screen]", "nFrameSkips")
        !           614:         print "Frameskip", fs
        !           615:         if fs < 0 or fs > 5:
        !           616:             return 5
        !           617:         return fs
        !           618:     
        !           619:     def set_frameskip(self, value):
        !           620:         value = int(value) # guarantee correct type
        !           621:         self.set("[Screen]", "nFrameSkips", value)
        !           622:         self._change_option("--frameskips %d" % value)
        !           623: 
        !           624:     # ------------ spec512 ---------------
        !           625:     def get_spec512threshold(self):
        !           626:         return self.get("[Screen]", "nSpec512Threshold")
        !           627: 
        !           628:     def set_spec512threshold(self, value):
        !           629:         value = int(value) # guarantee correct type
        !           630:         self.set("[Screen]", "nSpec512Threshold", value)
        !           631:         self._change_option("--spec512 %d" % value)
        !           632: 
        !           633:     # ------------ show borders ---------------
        !           634:     def get_borders(self):
        !           635:         return self.get("[Screen]", "bAllowOverscan")
        !           636:     
        !           637:     def set_borders(self, value):
        !           638:         self.set("[Screen]", "bAllowOverscan", value)
        !           639:         self._change_option("--borders %s" % str(value))
        !           640: 
        !           641:     # ------------ show statusbar ---------------
        !           642:     def get_statusbar(self):
        !           643:         return self.get("[Screen]", "bShowStatusbar")
        !           644:     
        !           645:     def set_statusbar(self, value):
        !           646:         self.set("[Screen]", "bShowStatusbar", value)
        !           647:         self._change_option("--statusbar %s" % str(value))
        !           648: 
        !           649:     # ------------ show led ---------------
        !           650:     def get_led(self):
        !           651:         return self.get("[Screen]", "bShowDriveLed")
        !           652:     
        !           653:     def set_led(self, value):
        !           654:         self.set("[Screen]", "bShowDriveLed", value)
        !           655:         self._change_option("--drive-led %s" % str(value))
        !           656: 
        !           657:     # ------------ monitor aspect ratio ---------------
        !           658:     def get_aspectcorrection(self):
        !           659:         return self.get("[Screen]", "bAspectCorrect")
        !           660:     
        !           661:     def set_aspectcorrection(self, value):
        !           662:         self.set("[Screen]", "bAspectCorrect", value)
        !           663:         self._change_option("--aspect %s" % str(value))
        !           664: 
        !           665:     # ------------ max window size ---------------
        !           666:     def get_max_size(self):
        !           667:         w = self.get("[Screen]", "nMaxWidth")
        !           668:         h = self.get("[Screen]", "nMaxHeight")
        !           669:         return (w, h)
        !           670: 
        !           671:     def set_max_size(self, w, h):
        !           672:         # guarantee correct type (Gtk float -> config int)
        !           673:         w = int(w); h = int(h)
        !           674:         self.set("[Screen]", "nMaxWidth", w)
        !           675:         self.set("[Screen]", "nMaxHeight", h)
        !           676:         self._change_option("--max-width %d" % w)
        !           677:         self._change_option("--max-height %d" % h)
        !           678: 
        !           679:     # TODO: remove once UI doesn't need this anymore
        !           680:     def set_zoom(self, value):
        !           681:         print "Just setting Zoom, configuration doesn't anymore have setting for this."
        !           682:         if value:
        !           683:             zoom = 2
        !           684:         else:
        !           685:             zoom = 1
        !           686:         self._change_option("--zoom %d" % zoom)
        !           687: 
        !           688:     # ------------ configured Hatari window size ---------------
        !           689:     def get_window_size(self):
        !           690:         if self.get("[Screen]", "bFullScreen"):
        !           691:             print "WARNING: don't start Hatari UI with fullscreened Hatari!"
        !           692: 
        !           693:         # VDI resolution?
        !           694:         if self.get("[Screen]", "bUseExtVdiResolutions"):
        !           695:             width = self.get("[Screen]", "nVdiWidth")
        !           696:             height = self.get("[Screen]", "nVdiHeight")
        !           697:             return (width, height)
        !           698:         
        !           699:         # window sizes for other than ST & STE can differ
        !           700:         if self.get("[System]", "nMachineType") not in (0, 1):
        !           701:             print "WARNING: neither ST nor STE machine, window size inaccurate!"
        !           702:             videl = True
        !           703:         else:
        !           704:             videl = False
        !           705: 
        !           706:         # mono monitor?
        !           707:         if self.get_monitor() == 0:
        !           708:             return (640, 400)
        !           709: 
        !           710:         # no, color
        !           711:         width = 320
        !           712:         height = 200
        !           713:         # statusbar?
        !           714:         if self.get_statusbar():
        !           715:             sbar = 12
        !           716:             height += sbar
        !           717:         else:
        !           718:             sbar = 0
        !           719:         # zoom?
        !           720:         maxw, maxh = self.get_max_size()
        !           721:         if 2*width <= maxw and 2*height <= maxh:
        !           722:             width *= 2
        !           723:             height *= 2
        !           724:             zoom = 2
        !           725:         else:
        !           726:             zoom = 1
        !           727:         # overscan borders?
        !           728:         if self.get_borders() and not videl:
        !           729:             # properly aligned borders on top of zooming
        !           730:             leftx = (maxw-width)/zoom
        !           731:             borderx = 2*(min(48,leftx/2)/16)*16
        !           732:             lefty = (maxh-height)/zoom
        !           733:             bordery = min(29+47, lefty)
        !           734:             width += zoom*borderx
        !           735:             height += zoom*bordery
        !           736: 
        !           737:         return (width, height)

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.