Annotation of hatari/python-ui/dialogs.py, revision 1.1.1.11

1.1       root        1: #!/usr/bin/env python
                      2: #
                      3: # Classes for the Hatari UI dialogs
                      4: #
1.1.1.10  root        5: # Copyright (C) 2008-2015 by Eero Tamminen
1.1       root        6: #
                      7: # This program is free software; you can redistribute it and/or modify
                      8: # it under the terms of the GNU General Public License as published by
                      9: # the Free Software Foundation; either version 2 of the License, or
                     10: # (at your option) any later version.
                     11: #
                     12: # This program is distributed in the hope that it will be useful,
                     13: # but WITHOUT ANY WARRANTY; without even the implied warranty of
                     14: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     15: # GNU General Public License for more details.
                     16: 
                     17: import os
                     18: # use correct version of pygtk/gtk
                     19: import pygtk
                     20: pygtk.require('2.0')
                     21: import gtk
                     22: import pango
                     23: 
                     24: from uihelpers import UInfo, HatariTextInsert, create_table_dialog, \
                     25:      table_add_entry_row, table_add_widget_row, table_add_separator, \
1.1.1.4   root       26:      table_add_radio_rows, table_set_col_offset, create_button, FselEntry, \
                     27:      FselAndEjectFactory
1.1       root       28: 
                     29: 
                     30: # -----------------
                     31: # Dialog base class
                     32: 
                     33: class HatariUIDialog:
                     34:     def __init__(self, parent):
                     35:         "<any>Dialog(parent) -> object"
                     36:         self.parent = parent
                     37:         self.dialog = None
                     38:     
                     39:     def run(self):
                     40:         """run() -> response. Shows dialog and returns response,
                     41: subclasses overriding run() require also an argument."""
                     42:         response = self.dialog.run()
                     43:         self.dialog.hide()
                     44:         return response
                     45: 
                     46: 
                     47: # ---------------------------
                     48: # Note/Todo/Error/Ask dialogs
                     49: 
                     50: class NoteDialog(HatariUIDialog):
1.1.1.3   root       51:     button = gtk.BUTTONS_OK
1.1       root       52:     icontype = gtk.MESSAGE_INFO
                     53:     textpattern = "\n%s"
                     54:     def run(self, text):
                     55:         "run(text), show message dialog with given text"
                     56:         dialog = gtk.MessageDialog(self.parent,
                     57:         gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
1.1.1.3   root       58:         self.icontype, self.button, self.textpattern % text)
1.1       root       59:         dialog.run()
                     60:         dialog.destroy()
                     61: 
                     62: class TodoDialog(NoteDialog):
                     63:     textpattern = "\nTODO: %s"
                     64: 
                     65: class ErrorDialog(NoteDialog):
1.1.1.3   root       66:     button = gtk.BUTTONS_CLOSE
1.1       root       67:     icontype = gtk.MESSAGE_ERROR
                     68:     textpattern = "\nERROR: %s"
                     69: 
                     70: 
                     71: class AskDialog(HatariUIDialog):
                     72:     def run(self, text):
                     73:         "run(text) -> bool, show question dialog and return True if user OKed it"
                     74:         dialog = gtk.MessageDialog(self.parent,
                     75:         gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                     76:         gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO, text)
                     77:         response = dialog.run()
                     78:         dialog.destroy()
                     79:         return (response == gtk.RESPONSE_YES)
                     80: 
                     81: 
                     82: # ---------------------------
                     83: # About dialog
                     84: 
                     85: class AboutDialog(HatariUIDialog):
                     86:     def __init__(self, parent):
                     87:         dialog = gtk.AboutDialog()
                     88:         dialog.set_transient_for(parent)
                     89:         dialog.set_name(UInfo.name)
                     90:         dialog.set_version(UInfo.version)
1.1.1.5   root       91:         dialog.set_website("http://hatari.tuxfamily.org/")
1.1       root       92:         dialog.set_website_label("Hatari emulator www-site")
                     93:         dialog.set_authors(["Eero Tamminen"])
                     94:         dialog.set_artists(["The logo is from Hatari"])
                     95:         dialog.set_logo(gtk.gdk.pixbuf_new_from_file(UInfo.logo))
                     96:         dialog.set_translator_credits("translator-credits")
1.1.1.3   root       97:         dialog.set_copyright(UInfo.copyright)
1.1       root       98:         dialog.set_license("""
1.1.1.2   root       99: This software is licenced under GPL v2 or later.
1.1       root      100: 
                    101: You can see the whole license at:
                    102:     http://www.gnu.org/licenses/info/GPLv2.html""")
                    103:         self.dialog = dialog
                    104: 
                    105: 
                    106: # ---------------------------
                    107: # Input dialog
                    108: 
                    109: class InputDialog(HatariUIDialog):
                    110:     def __init__(self, parent):
                    111:         dialog = gtk.Dialog("Key/mouse input", parent,
                    112:             gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                    113:             ("Close", gtk.RESPONSE_CLOSE))
                    114:         
                    115:         entry = gtk.Entry()
                    116:         entry.connect("activate", self._entry_cb)
                    117:         insert = create_button("Insert", self._entry_cb)
1.1.1.4   root      118:         insert.set_tooltip_text("Insert given text to Hatari window")
                    119:         enter = create_button("Enter key", self._enter_cb)
                    120:         enter.set_tooltip_text("Simulate Enter key press")
1.1       root      121: 
                    122:         hbox1 = gtk.HBox()
                    123:         hbox1.add(gtk.Label("Text:"))
                    124:         hbox1.add(entry)
                    125:         hbox1.add(insert)
1.1.1.4   root      126:         hbox1.add(enter)
1.1       root      127:         dialog.vbox.add(hbox1)
                    128: 
1.1.1.4   root      129:         rclick = gtk.Button("Right click")
1.1       root      130:         rclick.connect("pressed", self._rightpress_cb)
                    131:         rclick.connect("released", self._rightrelease_cb)
1.1.1.4   root      132:         rclick.set_tooltip_text("Simulate Atari right button press & release")
                    133:         dclick = create_button("Double click", self._doubleclick_cb)
                    134:         dclick.set_tooltip_text("Simulate Atari left button double-click")
1.1       root      135: 
                    136:         hbox2 = gtk.HBox()
                    137:         hbox2.add(dclick)
1.1.1.4   root      138:         hbox2.add(rclick)
1.1       root      139:         dialog.vbox.add(hbox2)
                    140: 
                    141:         dialog.show_all()
                    142:         self.dialog = dialog
                    143:         self.entry = entry
                    144:     
                    145:     def _entry_cb(self, widget):
                    146:         text = self.entry.get_text()
                    147:         if text:
                    148:             HatariTextInsert(self.hatari, text)
                    149:             self.entry.set_text("")
                    150: 
1.1.1.4   root      151:     def _enter_cb(self, widget):
                    152:         self.hatari.insert_event("keypress 28") # Enter key scancode
                    153: 
1.1       root      154:     def _doubleclick_cb(self, widget):
                    155:         self.hatari.insert_event("doubleclick")
                    156: 
                    157:     def _rightpress_cb(self, widget):
1.1.1.4   root      158:         self.hatari.insert_event("rightdown")
1.1       root      159: 
                    160:     def _rightrelease_cb(self, widget):
1.1.1.4   root      161:         self.hatari.insert_event("rightup")
1.1       root      162: 
                    163:     def run(self, hatari):
                    164:         "run(hatari), do text/mouse click input"
                    165:         self.hatari = hatari
                    166:         self.dialog.run()
                    167:         self.dialog.hide()
                    168: 
                    169: 
                    170: # ---------------------------
                    171: # Quit and Save dialog
                    172: 
                    173: class QuitSaveDialog(HatariUIDialog):
                    174:     def __init__(self, parent):
                    175:         dialog = gtk.Dialog("Quit and Save?", parent,
                    176:             gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                    177:             ("Save changes",    gtk.RESPONSE_YES,
                    178:              "Discard changes", gtk.RESPONSE_NO,
                    179:              gtk.STOCK_CANCEL,  gtk.RESPONSE_CANCEL))
                    180:         dialog.vbox.add(gtk.Label("You have unsaved configuration changes:"))
                    181:         viewport = gtk.Viewport()
                    182:         viewport.add(gtk.Label())
                    183:         scrolledwindow = gtk.ScrolledWindow()
                    184:         scrolledwindow.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
                    185:         scrolledwindow.add(viewport)
                    186:         dialog.vbox.add(scrolledwindow)
                    187:         dialog.show_all()
                    188:         self.scrolledwindow = scrolledwindow
                    189:         self.viewport = viewport
                    190:         self.dialog = dialog
                    191:         
                    192:     def run(self, config):
                    193:         "run(config) -> False if canceled, True otherwise or if no changes"
                    194:         changes = []
                    195:         for key, value in config.get_changes():
                    196:             changes.append("%s = %s" % (key, str(value)))
                    197:         if not changes:
                    198:             return True
                    199:         child = self.viewport.get_child()
                    200:         child.set_text(config.get_path() + ":\n" + "\n".join(changes))
                    201:         width, height = child.get_size_request()
                    202:         if height < 320:
                    203:             self.scrolledwindow.set_size_request(width, height)
                    204:         else:
                    205:             self.scrolledwindow.set_size_request(-1, 320)
                    206:         self.viewport.show_all()
                    207:         
                    208:         response = self.dialog.run()
                    209:         self.dialog.hide()
                    210:         if response == gtk.RESPONSE_CANCEL:
                    211:             return False
                    212:         if response == gtk.RESPONSE_YES:
                    213:             config.save()
                    214:         return True
                    215: 
                    216: 
                    217: # ---------------------------
                    218: # Kill Hatari dialog
                    219: 
                    220: class KillDialog(HatariUIDialog):
                    221:     def __init__(self, parent):
                    222:         self.dialog = gtk.MessageDialog(parent,
                    223:         gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                    224:         gtk.MESSAGE_QUESTION, gtk.BUTTONS_OK_CANCEL,
                    225:         """\
                    226: Hatari emulator is already/still running and it needs to be terminated first. However, if it contains unsaved data, that will be lost.
                    227: 
                    228: Terminate Hatari anyway?""")
                    229: 
                    230:     def run(self, hatari):
                    231:         "run(hatari) -> True if Hatari killed, False if left running"
                    232:         if not hatari.is_running():
                    233:             return True
                    234:         # Hatari is running, OK to kill?
                    235:         response = self.dialog.run()
                    236:         self.dialog.hide()
                    237:         if response == gtk.RESPONSE_OK:
                    238:             hatari.kill()
                    239:             return True
                    240:         return False
                    241: 
                    242:     
                    243: # ---------------------------
                    244: # Reset Hatari dialog
                    245: 
                    246: class ResetDialog(HatariUIDialog):
                    247:     COLD = 1
                    248:     WARM = 2
                    249:     def __init__(self, parent):
                    250:         self.dialog = gtk.Dialog("Reset Atari?", parent,
                    251:             gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                    252:             ("Cold reset", self.COLD, "Warm reset", self.WARM,
                    253:              gtk.STOCK_CANCEL,  gtk.RESPONSE_CANCEL))
                    254:         label = gtk.Label("\nRebooting will lose changes in currently\nrunning Atari programs.\n\nReset anyway?\n")
                    255:         self.dialog.vbox.add(label)
                    256:         label.show()
                    257: 
                    258:     def run(self, hatari):
                    259:         "run(hatari) -> True if Hatari rebooted, False if canceled"
                    260:         if not hatari.is_running():
                    261:             return False
                    262:         # Hatari is running, how to reboot?
                    263:         response = self.dialog.run()
                    264:         self.dialog.hide()
                    265:         if response == self.COLD:
                    266:             hatari.trigger_shortcut("coldreset")
                    267:         elif response == self.WARM:
                    268:             hatari.trigger_shortcut("warmreset")
                    269:         else:
                    270:             return False
                    271:         return True
                    272: 
                    273: 
                    274: # ----------------------------------
                    275: # Floppy image dialog
                    276: 
1.1.1.3   root      277: class FloppyDialog(HatariUIDialog):
1.1       root      278:     def _create_dialog(self, config):
1.1.1.3   root      279:         table, self.dialog = create_table_dialog(self.parent, "Floppy images", 4, 2)
1.1.1.4   root      280:         factory = FselAndEjectFactory()
1.1.1.3   root      281: 
1.1       root      282:         row = 0
                    283:         self.floppy = []
                    284:         path = config.get_floppydir()
                    285:         for drive in ("A", "B"):
1.1.1.9   root      286:             label = "Disk %c image:" % drive
1.1.1.4   root      287:             fname = config.get_floppy(row)
                    288:             fsel, box = factory.get(label, path, fname, gtk.FILE_CHOOSER_ACTION_OPEN)
1.1       root      289:             table_add_widget_row(table, row, label, box)
1.1.1.4   root      290:             self.floppy.append(fsel)
1.1       root      291:             row += 1
                    292: 
1.1.1.3   root      293:         protect = gtk.combo_box_new_text()
                    294:         for text in config.get_protection_types():
                    295:             protect.append_text(text)
                    296:         protect.set_active(config.get_floppy_protection())
1.1.1.4   root      297:         protect.set_tooltip_text("Write protect floppy image contents")
1.1.1.3   root      298:         table_add_widget_row(table, row, "Write protection:", protect)
1.1.1.9   root      299:         row += 1
1.1.1.3   root      300: 
1.1.1.9   root      301:         ds = gtk.CheckButton("Double sided drives")
                    302:         ds.set_active(config.get_doublesided())
                    303:         ds.set_tooltip_text("Whether drives are double or single sided. Can affect behavior of some games")
                    304:         table_add_widget_row(table, row, None, ds)
                    305:         row += 1
                    306:         
                    307:         driveb = gtk.CheckButton("Drive B connected")
                    308:         driveb.set_active(config.get_floppy_drives()[1])
                    309:         driveb.set_tooltip_text("Wheter drive B is connected. Can affect behavior of some demos & games")
                    310:         table_add_widget_row(table, row, None, driveb)
1.1.1.3   root      311:         row += 1
1.1.1.9   root      312: 
1.1.1.5   root      313:         fastfdc = gtk.CheckButton("Fast floppy access")
                    314:         fastfdc.set_active(config.get_fastfdc())
1.1.1.6   root      315:         fastfdc.set_tooltip_text("Can cause incompatibilities with some games/demos")
1.1.1.5   root      316:         table_add_widget_row(table, row, None, fastfdc)
1.1.1.3   root      317: 
1.1       root      318:         table.show_all()
                    319: 
1.1.1.3   root      320:         self.protect = protect
1.1.1.5   root      321:         self.fastfdc = fastfdc
1.1.1.9   root      322:         self.driveb = driveb
                    323:         self.ds = ds
1.1       root      324:     
                    325:     def run(self, config):
                    326:         "run(config), show disk image dialog"
                    327:         if not self.dialog:
                    328:             self._create_dialog(config)
                    329:         response = self.dialog.run()
                    330:         self.dialog.hide()
                    331:         
                    332:         if response == gtk.RESPONSE_APPLY:
                    333:             config.lock_updates()
                    334:             for drive in range(2):
                    335:                 config.set_floppy(drive, self.floppy[drive].get_filename())
1.1.1.4   root      336:             config.set_floppy_protection(self.protect.get_active())
1.1.1.9   root      337:             config.set_doublesided(self.ds.get_active())
1.1.1.5   root      338:             config.set_fastfdc(self.fastfdc.get_active())
1.1.1.9   root      339:             drives = (config.get_floppy_drives()[0], self.driveb.get_active())
                    340:             config.set_floppy_drives(drives)
1.1       root      341:             config.flush_updates()
                    342: 
1.1.1.3   root      343: 
                    344: # ----------------------------------
                    345: # Hard disk dialog
                    346: 
                    347: class HardDiskDialog(HatariUIDialog):
                    348:     def _create_dialog(self, config):
                    349:         table, self.dialog = create_table_dialog(self.parent, "Hard disks", 4, 4, "Set and reboot")
1.1.1.4   root      350:         factory = FselAndEjectFactory()
1.1.1.3   root      351: 
1.1.1.4   root      352:         row = 0
1.1.1.3   root      353:         label = "ASCI HD image:"
                    354:         path = config.get_acsi_image()
1.1.1.4   root      355:         fsel, box = factory.get(label, None, path, gtk.FILE_CHOOSER_ACTION_OPEN)
1.1.1.3   root      356:         table_add_widget_row(table, row, label, box, True)
                    357:         self.acsi = fsel
                    358:         row += 1
                    359: 
                    360:         label = "IDE HD master image:"
                    361:         path = config.get_idemaster_image()
1.1.1.4   root      362:         fsel, box = factory.get(label, None, path, gtk.FILE_CHOOSER_ACTION_OPEN)
1.1.1.3   root      363:         table_add_widget_row(table, row, label, box, True)
                    364:         self.idemaster = fsel
                    365:         row += 1
                    366: 
                    367:         label = "IDE HD slave image:"
                    368:         path = config.get_ideslave_image()
1.1.1.4   root      369:         fsel, box = factory.get(label, None, path, gtk.FILE_CHOOSER_ACTION_OPEN)
1.1.1.3   root      370:         table_add_widget_row(table, row, label, box, True)
                    371:         self.ideslave = fsel
                    372:         row += 1
1.1.1.10  root      373: 
                    374:         table_add_widget_row(table, row, " ", gtk.HSeparator(), True)
                    375:         row += 1
                    376: 
1.1.1.3   root      377:         label = "GEMDOS drive directory:"
1.1.1.10  root      378:         path = config.get_hd_dir()
1.1.1.4   root      379:         fsel, box = factory.get(label, None, path, gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER)
1.1.1.3   root      380:         table_add_widget_row(table, row, label, box, True)
1.1.1.10  root      381:         self.hddir = fsel
                    382:         row += 1
                    383: 
                    384:         hddrive = gtk.combo_box_new_text()
                    385:         for text in config.get_hd_drives():
                    386:             hddrive.append_text(text)
                    387:         hddrive.set_tooltip_text("Whether GEMDOS HD emulation uses fixed drive letter, or first free drive letter after ASCI & IDE drives (detection unreliable)")
                    388:         table_add_widget_row(table, row, "GEMDOS HD drive:", hddrive)
                    389:         self.hddrive = hddrive
1.1.1.3   root      390:         row += 1
                    391: 
                    392:         protect = gtk.combo_box_new_text()
                    393:         for text in config.get_protection_types():
                    394:             protect.append_text(text)
1.1.1.9   root      395:         protect.set_tooltip_text("Whether/how to write protect (GEMDOS HD) emulation files, 'auto' means using host files' own properties")
1.1.1.3   root      396:         table_add_widget_row(table, row, "Write protection:", protect)
                    397:         self.protect = protect
1.1.1.9   root      398:         row += 1
                    399:         
                    400:         lower = gtk.combo_box_new_text()
                    401:         for text in config.get_hd_cases():
                    402:             lower.append_text(text)
                    403:         lower.set_tooltip_text("What to do with names of files created by Atari programs through GEMDOS HD emulation")
                    404:         table_add_widget_row(table, row, "File names:", lower)
                    405:         self.lower = lower
1.1.1.3   root      406: 
                    407:         table.show_all()
1.1       root      408:     
1.1.1.3   root      409:     def _get_config(self, config):
                    410:         path = config.get_acsi_image()
                    411:         if path:
                    412:             self.acsi.set_filename(path)
                    413:         path = config.get_idemaster_image()
                    414:         if path:
                    415:             self.idemaster.set_filename(path)
                    416:         path = config.get_ideslave_image()
                    417:         if path:
                    418:             self.ideslave.set_filename(path)
1.1.1.10  root      419:         path = config.get_hd_dir()
                    420:         if path:
                    421:             self.hddir.set_filename(path)
                    422:         self.hddrive.set_active(config.get_hd_drive())
1.1.1.3   root      423:         self.protect.set_active(config.get_hd_protection())
1.1.1.9   root      424:         self.lower.set_active(config.get_hd_case())
                    425: 
1.1.1.3   root      426:     def _set_config(self, config):
                    427:         config.lock_updates()
                    428:         config.set_acsi_image(self.acsi.get_filename())
                    429:         config.set_idemaster_image(self.idemaster.get_filename())
                    430:         config.set_ideslave_image(self.ideslave.get_filename())
1.1.1.10  root      431:         config.set_hd_dir(self.hddir.get_filename())
                    432:         config.set_hd_drive(self.hddrive.get_active())
1.1.1.3   root      433:         config.set_hd_protection(self.protect.get_active())
1.1.1.9   root      434:         config.set_hd_case(self.lower.get_active())
1.1.1.3   root      435:         config.flush_updates()
                    436: 
                    437:     def run(self, config):
                    438:         "run(config) -> bool, whether to reboot"
                    439:         if not self.dialog:
                    440:             self._create_dialog(config)
                    441: 
                    442:         self._get_config(config)
                    443:         response = self.dialog.run()
                    444:         self.dialog.hide()
                    445:         if response == gtk.RESPONSE_APPLY:
                    446:             self._set_config(config)
                    447:             return True
                    448:         return False
                    449: 
                    450: 
1.1       root      451: # ---------------------------
                    452: # Display dialog
                    453: 
                    454: class DisplayDialog(HatariUIDialog):
                    455: 
                    456:     def _create_dialog(self, config):
                    457: 
                    458:         skip = gtk.combo_box_new_text()
                    459:         for text in config.get_frameskip_names():
                    460:             skip.append_text(text)
                    461:         skip.set_active(config.get_frameskip())
1.1.1.9   root      462:         skip.set_tooltip_text("Set how many frames are skipped to speed up emulation")
                    463: 
                    464:         slow = gtk.combo_box_new_text()
                    465:         for text in config.get_slowdown_names():
                    466:             slow.append_text(text)
                    467:         slow.set_active(0)
                    468:         slow.set_tooltip_text("VBL wait multiplier to slow down emulation. Breaks sound and large enough slowdown causes mouse clicks not to work.")
1.1       root      469: 
1.1.1.3   root      470:         maxw, maxh = config.get_max_size()
1.1.1.6   root      471:         topw, toph = config.get_desktop_size()
                    472:         maxadjw = gtk.Adjustment(maxw, 320, topw, 8, 40)
                    473:         maxadjh = gtk.Adjustment(maxh, 200, toph, 8, 40)
1.1.1.3   root      474:         scalew = gtk.HScale(maxadjw)
                    475:         scaleh = gtk.HScale(maxadjh)
                    476:         scalew.set_digits(0)
                    477:         scaleh.set_digits(0)
1.1.1.4   root      478:         scalew.set_tooltip_text("Preferred/maximum zoomed width")
                    479:         scaleh.set_tooltip_text("Preferred/maximum zoomed height")
                    480: 
1.1.1.7   root      481:         force_max = gtk.CheckButton("Force max resolution (Falcon)")
                    482:         force_max.set_active(config.get_force_max())
                    483:         force_max.set_tooltip_text("Whether to force maximum resolution to help recording videos of demos which do resolution changes")
                    484: 
                    485:         desktop = gtk.CheckButton("Keep desktop resolution (Falcon/TT)")
1.1.1.4   root      486:         desktop.set_active(config.get_desktop())
1.1.1.7   root      487:         desktop.set_tooltip_text("Whether to keep screen resolution in fullscreen and (try to) scale Atari screen by an integer factor instead")
                    488: 
                    489:         desktop_st = gtk.CheckButton("Keep desktop resolution (ST/STE)")
                    490:         desktop_st.set_active(config.get_desktop_st())
                    491:         desktop_st.set_tooltip_text("Whether to keep screen resolution in fullscreen to avoid potential sound skips + delay (NO SCALING)")
1.1       root      492: 
1.1.1.7   root      493:         borders = gtk.CheckButton("Atari screen borders")
1.1       root      494:         borders.set_active(config.get_borders())
1.1.1.7   root      495:         borders.set_tooltip_text("Whether to show overscan borders in ST/STE low/mid-rez or in Falcon color resolutions. Visible border area is affected by max. zoom size")
1.1       root      496: 
1.1.1.3   root      497:         statusbar = gtk.CheckButton("Show statusbar")
1.1       root      498:         statusbar.set_active(config.get_statusbar())
1.1.1.4   root      499:         statusbar.set_tooltip_text("Whether to show statusbar with floppy leds etc")
1.1       root      500: 
1.1.1.3   root      501:         led = gtk.CheckButton("Show overlay led")
1.1       root      502:         led.set_active(config.get_led())
1.1.1.4   root      503:         led.set_tooltip_text("Whether to show overlay drive led when statusbar isn't visible")
                    504: 
                    505:         crop = gtk.CheckButton("Remove statusbar from screen capture")
                    506:         crop.set_active(config.get_crop())
                    507:         crop.set_tooltip_text("Whether to crop statusbar from screenshots and video recordings")
1.1       root      508: 
                    509:         dialog = gtk.Dialog("Display settings", self.parent,
                    510:             gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                    511:             (gtk.STOCK_APPLY,  gtk.RESPONSE_APPLY,
                    512:              gtk.STOCK_CANCEL,  gtk.RESPONSE_CANCEL))
                    513: 
1.1.1.3   root      514:         dialog.vbox.add(gtk.Label("Max zoomed size:"))
                    515:         dialog.vbox.add(scalew)
                    516:         dialog.vbox.add(scaleh)
1.1.1.7   root      517:         dialog.vbox.add(force_max)
1.1.1.4   root      518:         dialog.vbox.add(desktop)
1.1.1.7   root      519:         dialog.vbox.add(desktop_st)
1.1       root      520:         dialog.vbox.add(borders)
1.1.1.9   root      521:         dialog.vbox.add(gtk.Label("Frameskip:"))
                    522:         dialog.vbox.add(skip)
                    523:         dialog.vbox.add(gtk.Label("Slowdown:"))
                    524:         dialog.vbox.add(slow)
1.1       root      525:         dialog.vbox.add(statusbar)
                    526:         dialog.vbox.add(led)
1.1.1.4   root      527:         dialog.vbox.add(crop)
1.1       root      528:         dialog.vbox.show_all()
                    529: 
                    530:         self.dialog = dialog
                    531:         self.skip = skip
1.1.1.9   root      532:         self.slow = slow
1.1.1.3   root      533:         self.maxw = maxadjw
                    534:         self.maxh = maxadjh
1.1.1.7   root      535:         self.force_max = force_max
1.1.1.4   root      536:         self.desktop = desktop
1.1.1.7   root      537:         self.desktop_st = desktop_st
1.1       root      538:         self.borders = borders
                    539:         self.statusbar = statusbar
                    540:         self.led = led
1.1.1.4   root      541:         self.crop = crop
1.1       root      542:  
                    543:     def run(self, config):
                    544:         "run(config), show display dialog"
                    545:         if not self.dialog:
                    546:             self._create_dialog(config)
                    547:         response = self.dialog.run()
                    548:         self.dialog.hide()
                    549:         if response == gtk.RESPONSE_APPLY:
                    550:             config.lock_updates()
                    551:             config.set_frameskip(self.skip.get_active())
1.1.1.9   root      552:             config.set_slowdown(self.slow.get_active())
1.1.1.3   root      553:             config.set_max_size(self.maxw.get_value(), self.maxh.get_value())
1.1.1.7   root      554:             config.set_force_max(self.force_max.get_active())
1.1.1.4   root      555:             config.set_desktop(self.desktop.get_active())
1.1.1.7   root      556:             config.set_desktop_st(self.desktop_st.get_active())
1.1       root      557:             config.set_borders(self.borders.get_active())
                    558:             config.set_statusbar(self.statusbar.get_active())
                    559:             config.set_led(self.led.get_active())
1.1.1.4   root      560:             config.set_crop(self.crop.get_active())
1.1       root      561:             config.flush_updates()
                    562: 
                    563: 
                    564: # ----------------------------------
                    565: # Joystick dialog
                    566: 
                    567: class JoystickDialog(HatariUIDialog):
                    568:     def _create_dialog(self, config):
1.1.1.3   root      569:         table, self.dialog = create_table_dialog(self.parent, "Joystick settings", 9, 2)
1.1       root      570:         
                    571:         joy = 0
                    572:         self.joy = []
                    573:         joytypes = config.get_joystick_types()
                    574:         for label in config.get_joystick_names():
                    575:             combo = gtk.combo_box_new_text()
                    576:             for text in joytypes:
                    577:                 combo.append_text(text)
                    578:             combo.set_active(config.get_joystick(joy))
                    579:             widget = table_add_widget_row(table, joy, "%s:" % label, combo)
                    580:             self.joy.append(widget)
                    581:             joy += 1
                    582: 
                    583:         table.show_all()
                    584:     
                    585:     def run(self, config):
                    586:         "run(config), show joystick dialog"
                    587:         if not self.dialog:
                    588:             self._create_dialog(config)
                    589:         response = self.dialog.run()
                    590:         self.dialog.hide()
                    591:         
                    592:         if response == gtk.RESPONSE_APPLY:
                    593:             config.lock_updates()
                    594:             for joy in range(6):
                    595:                 config.set_joystick(joy, self.joy[joy].get_active())
                    596:             config.flush_updates()
                    597: 
                    598: 
                    599: # ---------------------------------------
                    600: # Peripherals (midi,printer,rs232) dialog
                    601: 
                    602: class PeripheralDialog(HatariUIDialog):
                    603:     def _create_dialog(self, config):
                    604:         midi = gtk.CheckButton("Enable MIDI")
                    605:         midi.set_active(config.get_midi())
                    606: 
                    607:         printer = gtk.CheckButton("Enable printer output")
                    608:         printer.set_active(config.get_printer())
                    609: 
                    610:         rs232 = gtk.CheckButton("Enable RS232")
                    611:         rs232.set_active(config.get_rs232())
                    612: 
                    613:         dialog = gtk.Dialog("Peripherals", self.parent,
                    614:             gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                    615:             (gtk.STOCK_APPLY,  gtk.RESPONSE_APPLY,
                    616:              gtk.STOCK_CANCEL,  gtk.RESPONSE_CANCEL))
                    617:         dialog.vbox.add(midi)
                    618:         dialog.vbox.add(printer)
                    619:         dialog.vbox.add(rs232)
                    620:         dialog.vbox.show_all()
                    621: 
                    622:         self.dialog = dialog
                    623:         self.printer = printer
                    624:         self.rs232 = rs232
                    625:         self.midi = midi
                    626:     
                    627:     def run(self, config):
                    628:         "run(config), show peripherals dialog"
                    629:         if not self.dialog:
                    630:             self._create_dialog(config)
                    631:         response = self.dialog.run()
                    632:         self.dialog.hide()
                    633:         
                    634:         if response == gtk.RESPONSE_APPLY:
                    635:             config.lock_updates()
                    636:             config.set_midi(self.midi.get_active())
                    637:             config.set_printer(self.printer.get_active())
                    638:             config.set_rs232(self.rs232.get_active())
                    639:             config.flush_updates()
                    640: 
                    641: 
                    642: # ---------------------------------------
                    643: # Path dialog
                    644: 
                    645: class PathDialog(HatariUIDialog):
                    646:     def _create_dialog(self, config):
                    647:         paths = config.get_paths()
1.1.1.3   root      648:         table, self.dialog = create_table_dialog(self.parent, "File path settings", len(paths), 2)
1.1       root      649:         paths.sort()
                    650:         row = 0
                    651:         self.paths = []
                    652:         for (key, path, label) in paths:
                    653:             fsel = FselEntry(self.dialog, self._validate_fname, key)
                    654:             fsel.set_filename(path)
                    655:             self.paths.append((key, fsel))
                    656:             table_add_widget_row(table, row, label, fsel.get_container())
                    657:             row += 1
                    658:         table.show_all()
                    659:     
                    660:     def _validate_fname(self, key, fname):
                    661:         if key != "soundout":
                    662:             return True
                    663:         if fname.rsplit(".", 1)[-1].lower() in ("ym", "wav"):
                    664:             return True
                    665:         ErrorDialog(self.dialog).run("Sound output file name:\n\t%s\nneeds to end with '.ym' or '.wav'." % fname)
                    666:         return False
                    667:     
                    668:     def run(self, config):
                    669:         "run(config), show paths dialog"
                    670:         if not self.dialog:
                    671:             self._create_dialog(config)
                    672:         response = self.dialog.run()
                    673:         self.dialog.hide()
                    674: 
                    675:         if response == gtk.RESPONSE_APPLY:
                    676:             paths = []
                    677:             for key, fsel in self.paths:
                    678:                 paths.append((key, fsel.get_filename()))
                    679:             config.set_paths(paths)
                    680: 
                    681: 
                    682: # ---------------------------
                    683: # Sound dialog
                    684: 
                    685: class SoundDialog(HatariUIDialog):
                    686: 
                    687:     def _create_dialog(self, config):
1.1.1.6   root      688:         enabled, curhz = config.get_sound()
                    689: 
1.1       root      690:         self.enabled = gtk.CheckButton("Sound enabled")
                    691:         self.enabled.set_active(enabled)
1.1.1.6   root      692: 
                    693:         hz = gtk.combo_box_new_text()
                    694:         for text in config.get_sound_values():
                    695:             hz.append_text(text)
                    696:         hz.set_active(curhz)
                    697:         self.hz = hz
                    698: 
                    699:         ymmixer = gtk.combo_box_new_text()
                    700:         for text in config.get_ymmixer_types():
                    701:             ymmixer.append_text(text)
                    702:         ymmixer.set_active(config.get_ymmixer())
                    703:         self.ymmixer = ymmixer
                    704: 
1.1.1.9   root      705:         adj = gtk.Adjustment(config.get_bufsize(), 0, 110, 10, 10, 10)
                    706:         bufsize = gtk.HScale(adj)
                    707:         bufsize.set_digits(0)
                    708:         bufsize.set_tooltip_text("0 = use default value. In some situations, SDL default may cause large (~0.5s) sound delay at lower frequency.  If you have this problem, try with e.g. 20 ms, otherwise keep at 0.")
                    709:         self.bufsize = bufsize
                    710: 
                    711:         self.sync = gtk.CheckButton("Emulation speed synched to sound output")
                    712:         self.sync.set_tooltip_text("Constantly adjust emulation screen update rate to match sound output. Can help if you suffer from sound buffer under/overflow.")
                    713:         self.sync.set_active(config.get_sync())
                    714: 
1.1.1.6   root      715:         self.mic = gtk.CheckButton("Enable (Falcon) microphone")
                    716:         self.mic.set_active(config.get_mic())
1.1       root      717: 
                    718:         dialog = gtk.Dialog("Sound settings", self.parent,
                    719:             gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                    720:             (gtk.STOCK_APPLY,  gtk.RESPONSE_APPLY,
                    721:              gtk.STOCK_CANCEL,  gtk.RESPONSE_CANCEL))
                    722:         dialog.vbox.add(self.enabled)
1.1.1.6   root      723:         dialog.vbox.add(gtk.Label("Sound frequency::"))
                    724:         dialog.vbox.add(hz)
                    725:         dialog.vbox.add(gtk.Label("YM voices mixing method:"))
                    726:         dialog.vbox.add(ymmixer)
1.1.1.9   root      727:         dialog.vbox.add(gtk.Label("SDL sound buffer size (ms):"))
                    728:         dialog.vbox.add(bufsize)
                    729:         dialog.vbox.add(self.sync)
1.1.1.6   root      730:         dialog.vbox.add(self.mic)
1.1       root      731:         dialog.vbox.show_all()
                    732:         self.dialog = dialog
                    733: 
                    734:     def run(self, config):
                    735:         "run(config), show sound dialog"
                    736:         if not self.dialog:
                    737:             self._create_dialog(config)
                    738:         response = self.dialog.run()
                    739:         self.dialog.hide()
                    740:         if response == gtk.RESPONSE_APPLY:
1.1.1.6   root      741:             config.lock_updates()
                    742:             config.set_mic(self.mic.get_active())
1.1.1.9   root      743:             config.set_sync(self.sync.get_active())
                    744:             config.set_bufsize(self.bufsize.get_value())
1.1.1.6   root      745:             config.set_ymmixer(self.ymmixer.get_active())
1.1       root      746:             enabled = self.enabled.get_active()
1.1.1.6   root      747:             hz = self.hz.get_active()
                    748:             config.set_sound(enabled, hz)
                    749:             config.flush_updates()
1.1       root      750:         
                    751: 
                    752: # ---------------------------
                    753: # Trace settings dialog
                    754: 
                    755: class TraceDialog(HatariUIDialog):
                    756:     # you can get this list with:
                    757:     # hatari --trace help 2>&1|awk '/all$/{next} /^  [^-]/ {printf("\"%s\",\n", $1)}'
                    758:     tracepoints = [
                    759:         "video_sync",
                    760:         "video_res",
                    761:         "video_color",
                    762:         "video_border_v",
                    763:         "video_border_h",
                    764:         "video_addr",
                    765:         "video_hbl",
                    766:         "video_vbl",
                    767:         "video_ste",
                    768:         "mfp_exception",
                    769:         "mfp_start",
                    770:         "mfp_read",
                    771:         "mfp_write",
1.1.1.4   root      772:         "psg_read",
                    773:         "psg_write",
1.1       root      774:         "cpu_pairing",
                    775:         "cpu_disasm",
                    776:         "cpu_exception",
                    777:         "int",
                    778:         "fdc",
1.1.1.8   root      779:         "acia",
1.1       root      780:         "ikbd_cmds",
                    781:         "ikbd_acia",
                    782:         "ikbd_exec",
                    783:         "blitter",
                    784:         "bios",
                    785:         "xbios",
                    786:         "gemdos",
                    787:         "vdi",
1.1.1.4   root      788:         "aes",
1.1       root      789:         "io_read",
                    790:         "io_write",
1.1.1.4   root      791:         "dmasound",
                    792:         "crossbar",
                    793:         "videl",
                    794:         "dsp_host_interface",
                    795:         "dsp_host_command",
                    796:         "dsp_host_ssi",
                    797:         "dsp_interrupt",
                    798:         "dsp_disasm",
1.1.1.8   root      799:         "dsp_disasm_reg",
                    800:         "dsp_disasm_mem",
                    801:         "dsp_state",
                    802:         "dsp_symbols",
                    803:         "cpu_symbols",
1.1.1.9   root      804:         "nvram",
                    805:         "scsi_cmd",
                    806:         "natfeats",
1.1.1.10  root      807:         "keymap",
                    808:         "midi",
                    809:         "ide",
1.1.1.11! root      810:         "os_base",
        !           811:         "scsidrv"
1.1       root      812:     ]
                    813:     def __init__(self, parent):
1.1.1.6   root      814:         self.savedpoints = None
1.1       root      815:         hbox1 = gtk.HBox()
                    816:         hbox1.add(create_button("Load", self._load_traces))
                    817:         hbox1.add(create_button("Clear", self._clear_traces))
                    818:         hbox1.add(create_button("Save", self._save_traces))
                    819:         hbox2 = gtk.HBox()
                    820:         vboxes = []
1.1.1.4   root      821:         for idx in (0,1,2,3):
1.1       root      822:             vboxes.append(gtk.VBox())
                    823:             hbox2.add(vboxes[idx])
                    824: 
                    825:         count = 0
1.1.1.4   root      826:         per_side = (len(self.tracepoints)+3)/4
1.1       root      827:         self.tracewidgets = {}
                    828:         for trace in self.tracepoints:
1.1.1.2   root      829:             name = trace.replace("_", "-")
                    830:             widget = gtk.CheckButton(name)
1.1       root      831:             self.tracewidgets[trace] = widget
                    832:             vboxes[count/per_side].pack_start(widget, False, True)
                    833:             count += 1
                    834:         
                    835:         dialog = gtk.Dialog("Trace settings", parent,
                    836:             gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                    837:             (gtk.STOCK_APPLY,  gtk.RESPONSE_APPLY,
                    838:              gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))
                    839:         dialog.vbox.add(hbox1)
                    840:         dialog.vbox.add(gtk.Label("Select trace points:"))
                    841:         dialog.vbox.add(hbox2)
                    842:         dialog.vbox.show_all()
                    843:         self.dialog = dialog
                    844: 
                    845:     def _get_traces(self):
                    846:         traces = []
                    847:         for trace in self.tracepoints:
                    848:             if self.tracewidgets[trace].get_active():
                    849:                 traces.append(trace)
                    850:         if traces:
                    851:             return ",".join(traces)
                    852:         return "none"
                    853: 
                    854:     def _set_traces(self, tracepoints):
                    855:         self._clear_traces()
1.1.1.6   root      856:         if not tracepoints:
                    857:             return
1.1       root      858:         for trace in tracepoints.split(","):
                    859:             if trace in self.tracewidgets:
                    860:                 self.tracewidgets[trace].set_active(True)
                    861:             else:
1.1.1.4   root      862:                 print("ERROR: unknown trace setting '%s'" % trace)
1.1       root      863: 
                    864:     def _clear_traces(self, widget = None):
                    865:         for trace in self.tracepoints:
                    866:             self.tracewidgets[trace].set_active(False)
                    867: 
                    868:     def _load_traces(self, widget):
                    869:         # this doesn't load traces, just sets them from internal variable
                    870:         # that run method gets from caller and sets. It's up to caller
                    871:         # whether the saving or loading happens actually to disk
                    872:         self._set_traces(self.savedpoints)
                    873:     
                    874:     def _save_traces(self, widget):
                    875:         self.savedpoints = self._get_traces()
                    876: 
                    877:     def run(self, hatari, savedpoints):
                    878:         "run(hatari,tracepoints) -> tracepoints, caller saves tracepoints"
                    879:         self.savedpoints = savedpoints
                    880:         while 1:
                    881:             response = self.dialog.run()
                    882:             if response == gtk.RESPONSE_APPLY:
                    883:                 hatari.change_option("--trace %s" % self._get_traces())
                    884:             else:
                    885:                 self.dialog.hide()
                    886:                 return self.savedpoints
                    887: 
                    888: 
                    889: # ------------------------------------------
                    890: # Machine dialog for settings needing reboot
                    891: 
                    892: class MachineDialog(HatariUIDialog):
1.1.1.3   root      893:     def _machine_cb(self, widget, data):
                    894:         if not widget.get_active():
                    895:             return
                    896:         machine = data.lower()
                    897:         if machine == "ste" or machine == "st":
                    898:             self.clocks[0].set_active(True)
                    899:             self.cpulevel.set_active(0)
                    900:         elif machine == "falcon":
                    901:             self.clocks[1].set_active(True)
1.1.1.4   root      902:             self.dsps[2].set_active(True)
1.1.1.3   root      903:             self.cpulevel.set_active(3)
                    904:         elif machine == "tt":
                    905:             self.clocks[2].set_active(True)
                    906:             self.cpulevel.set_active(3)
                    907: 
1.1       root      908:     def _create_dialog(self, config):
1.1.1.3   root      909:         table, self.dialog = create_table_dialog(self.parent, "Machine configuration", 6, 4, "Set and reboot")
                    910:         
                    911:         row = 0
                    912:         self.machines = table_add_radio_rows(table, row, "Machine:",
                    913:                         config.get_machine_types(), self._machine_cb)
                    914:         row += 1
1.1       root      915: 
1.1.1.4   root      916:         self.dsps = table_add_radio_rows(table, row, "DSP type:", config.get_dsp_types())
1.1.1.3   root      917:         row += 1
                    918: 
                    919:         # start next table column
1.1       root      920:         row = 0
1.1.1.3   root      921:         table_set_col_offset(table, 2)
                    922:         self.monitors = table_add_radio_rows(table, row, "Monitor:", config.get_monitor_types())
1.1       root      923:         row += 1
1.1.1.3   root      924: 
                    925:         self.clocks = table_add_radio_rows(table, row, "CPU clock:", config.get_cpuclock_types())
                    926:         row += 1
                    927: 
                    928:         # fullspan at bottom
                    929:         fullspan = True
                    930: 
1.1       root      931:         combo = gtk.combo_box_new_text()
1.1.1.3   root      932:         for text in config.get_cpulevel_types():
1.1       root      933:             combo.append_text(text)
1.1.1.3   root      934:         self.cpulevel = table_add_widget_row(table, row, "CPU type:", combo, fullspan)
1.1       root      935:         row += 1
1.1.1.3   root      936: 
1.1       root      937:         combo = gtk.combo_box_new_text()
                    938:         for text in config.get_memory_names():
                    939:             combo.append_text(text)
1.1.1.3   root      940:         self.memory = table_add_widget_row(table, row, "Memory:", combo, fullspan)
1.1       root      941:         row += 1
1.1.1.10  root      942: 
                    943:         self.ttram = gtk.Adjustment(config.get_ttram(), 0, 260, 4, 4, 4)
                    944:         ttram = gtk.HScale(self.ttram)
                    945:         ttram.set_digits(0)
                    946:         ttram.set_tooltip_text("TT-RAM needs Falcon/TT with WinUAE CPU core and implies 32-bit addressing.  0 = disabled, 24-bit addressing.")
                    947:         table_add_widget_row(table, row, "TT-RAM", ttram, fullspan)
                    948:         row += 1
1.1       root      949:         
                    950:         label = "TOS image:"
                    951:         fsel = self._fsel(label, gtk.FILE_CHOOSER_ACTION_OPEN)
1.1.1.3   root      952:         self.tos = table_add_widget_row(table, row, label, fsel, fullspan)
1.1       root      953:         row += 1
                    954: 
1.1.1.3   root      955:         vbox = gtk.VBox()
                    956:         self.compatible = gtk.CheckButton("Compatible CPU")
1.1.1.4   root      957:         self.rtc = gtk.CheckButton("Real-time clock")
1.1.1.3   root      958:         self.timerd = gtk.CheckButton("Patch Timer-D")
1.1.1.9   root      959:         self.compatible.set_tooltip_text("Needed for overscan and other timing sensitive things to work correctly")
                    960:         self.rtc.set_tooltip_text("Some rare games and demos don't work with this")
                    961:         self.timerd.set_tooltip_text("Improves ST/STE emulation performance, but some rare demos/games don't work with this")
1.1.1.3   root      962:         vbox.add(self.compatible)
                    963:         vbox.add(self.timerd)
1.1.1.4   root      964:         vbox.add(self.rtc)
1.1.1.3   root      965:         table_add_widget_row(table, row, "Misc.:", vbox, fullspan)
1.1       root      966:         row += 1
                    967: 
                    968:         table.show_all()
                    969: 
                    970:     def _fsel(self, label, action):
                    971:         fsel = gtk.FileChooserButton(label)
                    972:         # Hatari cannot access URIs
                    973:         fsel.set_local_only(True)
                    974:         fsel.set_width_chars(12)
                    975:         fsel.set_action(action)
                    976:         return fsel
                    977:     
                    978:     def _get_config(self, config):
1.1.1.3   root      979:         self.machines[config.get_machine()].set_active(True)
                    980:         self.monitors[config.get_monitor()].set_active(True)
                    981:         self.clocks[config.get_cpuclock()].set_active(True)
                    982:         self.dsps[config.get_dsp()].set_active(True)
                    983:         self.cpulevel.set_active(config.get_cpulevel())
1.1       root      984:         self.memory.set_active(config.get_memory())
1.1.1.10  root      985:         self.ttram.set_value(config.get_ttram())
1.1       root      986:         tos = config.get_tos()
                    987:         if tos:
                    988:             self.tos.set_filename(tos)
                    989:         self.compatible.set_active(config.get_compatible())
                    990:         self.timerd.set_active(config.get_timerd())
1.1.1.4   root      991:         self.rtc.set_active(config.get_rtc())
1.1       root      992: 
1.1.1.3   root      993:     def _get_active_radio(self, radios):
                    994:         idx = 0
                    995:         for radio in radios:
                    996:             if radio.get_active():
                    997:                 return idx
                    998:             idx += 1
                    999:         
1.1       root     1000:     def _set_config(self, config):
                   1001:         config.lock_updates()
1.1.1.3   root     1002:         config.set_machine(self._get_active_radio(self.machines))
                   1003:         config.set_monitor(self._get_active_radio(self.monitors))
                   1004:         config.set_cpuclock(self._get_active_radio(self.clocks))
                   1005:         config.set_dsp(self._get_active_radio(self.dsps))
                   1006:         config.set_cpulevel(self.cpulevel.get_active())
1.1       root     1007:         config.set_memory(self.memory.get_active())
1.1.1.10  root     1008:         config.set_ttram(self.ttram.get_value())
1.1       root     1009:         config.set_tos(self.tos.get_filename())
                   1010:         config.set_compatible(self.compatible.get_active())
                   1011:         config.set_timerd(self.timerd.get_active())
1.1.1.4   root     1012:         config.set_rtc(self.rtc.get_active())
1.1       root     1013:         config.flush_updates()
                   1014: 
                   1015:     def run(self, config):
                   1016:         "run(config) -> bool, whether to reboot"
                   1017:         if not self.dialog:
                   1018:             self._create_dialog(config)
                   1019: 
                   1020:         self._get_config(config)
                   1021:         response = self.dialog.run()
                   1022:         self.dialog.hide()
                   1023:         if response == gtk.RESPONSE_APPLY:
                   1024:             self._set_config(config)
                   1025:             return True
                   1026:         return False

unix.superglobalmegacorp.com

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