diff --git a/gdb-gui.py.in b/gdb-gui.py.in index cd661f6..f704799 100644 --- a/gdb-gui.py.in +++ b/gdb-gui.py.in @@ -1,3 +1,4 @@ import sys -sys.path.append('HERE') + +sys.path.append("HERE") import gui.commands diff --git a/gui/adapt.py b/gui/adapt.py index 2210583..9c0d5f6 100644 --- a/gui/adapt.py +++ b/gui/adapt.py @@ -24,18 +24,15 @@ bugs = { 15620: """Your gdb doesn't have a "new breakpoint" event. This means that the source windows will not show you where breakpoints have been set.""", - 13598: """Your gdb doesn't have a "before prompt" event. This means that various windows won't be able to react to commands like "up" or "down".""", - 18385: """Your gdb doesn't expose locations on a gdb.Breakpoint. This can be worked around, but maybe not always reliably. This means that sometimes breakpoints won't display in source windows.""", - 18620: """Your gdb doesn't have a "breakpoint modified" event. This means that when a pending breakpoint is resolved, the GUI won't -be able to update to reflect that fact.""" +be able to update to reflect that fact.""", } _warning = """See https://sourceware.org/bugzilla/show_bug.cgi?id=%s @@ -43,6 +40,7 @@ for more information.""" _first_report = True + def notify_bug(bugno): if not gui.params.warn_missing.value: return diff --git a/gui/bpcache.py b/gui/bpcache.py index fb342d2..dc33910 100644 --- a/gui/bpcache.py +++ b/gui/bpcache.py @@ -22,6 +22,7 @@ import gui.adapt # destroyed. _breakpoint_source_map = {} + def _breakpoint_created(bp): if bp.location is None: return @@ -45,6 +46,7 @@ def _breakpoint_created(bp): else: _breakpoint_source_map[entry].add(bp.number) + def _breakpoint_deleted(bp): num = bp.number for entry in _breakpoint_source_map: @@ -53,25 +55,28 @@ def _breakpoint_deleted(bp): if len(_breakpoint_source_map[entry]) == 0: gui.events.location_changed.post(entry, False) + def _breakpoint_modified(bp): if bp.enabled: _breakpoint_created(bp) else: _breakpoint_deleted(bp) + def any_breakpoint_at(filename, lineno): entry = (filename, lineno) if entry not in _breakpoint_source_map: return False return len(_breakpoint_source_map[entry]) > 0 -if not hasattr(gdb.events, 'breakpoint_created'): + +if not hasattr(gdb.events, "breakpoint_created"): gui.adapt.notify_bug(15620) else: gdb.events.breakpoint_created.connect(_breakpoint_created) gdb.events.breakpoint_deleted.connect(_breakpoint_deleted) -if not hasattr(gdb.events, 'breakpoint_modified'): +if not hasattr(gdb.events, "breakpoint_modified"): gui.adapt.notify_bug(18620) else: gdb.events.breakpoint_modified.connect(_breakpoint_modified) diff --git a/gui/commands.py b/gui/commands.py index 606c462..6715e8d 100644 --- a/gui/commands.py +++ b/gui/commands.py @@ -27,33 +27,33 @@ import gui.adapt import re from gui.startup import in_gtk_thread + class GuiCommand(gdb.Command): def __init__(self): - super(GuiCommand, self).__init__('gui', gdb.COMMAND_SUPPORT, - prefix = True) + super(GuiCommand, self).__init__("gui", gdb.COMMAND_SUPPORT, prefix=True) + class GuiSourceCommand(gdb.Command): """Create a new source window. -Usage: gui source -This creates a new source window in the GUI. Any number of source -windows can be created.""" + Usage: gui source + This creates a new source window in the GUI. Any number of source + windows can be created.""" def __init__(self): - super(GuiSourceCommand, self).__init__('gui source', - gdb.COMMAND_SUPPORT) + super(GuiSourceCommand, self).__init__("gui source", gdb.COMMAND_SUPPORT) def invoke(self, arg, from_tty): self.dont_repeat() gui.source.lru_handler.new_source_window() + class GuiStackCommand(gdb.Command): """Create a new stack window. -Usage: gui stack -This creates a stack window in the GUI if it does not already exist.""" + Usage: gui stack + This creates a stack window in the GUI if it does not already exist.""" def __init__(self): - super(GuiStackCommand, self).__init__('gui stack', - gdb.COMMAND_SUPPORT) + super(GuiStackCommand, self).__init__("gui stack", gdb.COMMAND_SUPPORT) def invoke(self, arg, from_tty): self.dont_repeat() @@ -64,45 +64,45 @@ This creates a stack window in the GUI if it does not already exist.""" # or maybe even whatever 'bt' takes? gui.stack.show_stack() + class GuiListCommand(gdb.Command): """List some source code in a source window. -Usage: gui list LINESPEC -This command uses LINESPEC to show some source code in a source -window. If a source window is already available, the source is -displayed there. Otherwise, a new source window is made. -LINESPEC is a line specification of the form given to 'break'.""" + Usage: gui list LINESPEC + This command uses LINESPEC to show some source code in a source + window. If a source window is already available, the source is + displayed there. Otherwise, a new source window is made. + LINESPEC is a line specification of the form given to 'break'.""" def __init__(self): - super(GuiListCommand, self).__init__('gui list', - gdb.COMMAND_SUPPORT) + super(GuiListCommand, self).__init__("gui list", gdb.COMMAND_SUPPORT) def invoke(self, arg, from_tty): self.dont_repeat() (extra, sals) = gdb.decode_line(arg) if extra is not None: - raise gdb.GdbError('unrecognized junk at end of command: ' + extra) + raise gdb.GdbError("unrecognized junk at end of command: " + extra) if sals is None: - raise gdb.GdbError('not found') + raise gdb.GdbError("not found") if len(sals) > 1: print("Ambiguous linespec, only showing first result") sal = sals[0] if sal.symtab is None or sal.symtab.filename is None: - raise gdb.GdbError('could not find file for symbol') - gui.source.lru_handler.show_source_gdb(None, sal.symtab, - sal.symtab.fullname(), - sal.line) + raise gdb.GdbError("could not find file for symbol") + gui.source.lru_handler.show_source_gdb( + None, sal.symtab, sal.symtab.fullname(), sal.line + ) + class GuiShowCommand(gdb.Command): """Show the source for a symbol in a source window. -Usage: gui show SYMBOL -This command looks for the definition of SYMBOL in the program and -shows its source location in a source window. If a source window is -already available, the source is displayed there. Otherwise, a new -source window is made.""" + Usage: gui show SYMBOL + This command looks for the definition of SYMBOL in the program and + shows its source location in a source window. If a source window is + already available, the source is displayed there. Otherwise, a new + source window is made.""" def __init__(self): - super(GuiShowCommand, self).__init__('gui show', - gdb.COMMAND_SUPPORT) + super(GuiShowCommand, self).__init__("gui show", gdb.COMMAND_SUPPORT) def invoke(self, arg, from_tty): self.dont_repeat() @@ -113,101 +113,110 @@ source window is made.""" raise symbol = gdb.lookup_global_symbol(arg) if symbol is None: - raise gdb.GdbError('symbol ' + arg + ' not found') + raise gdb.GdbError("symbol " + arg + " not found") if symbol.symtab is None or symbol.symtab.filename is None: - raise gdb.GdbError('symbol ' + arg - + ' does not seem to have an associated file') - gui.source.lru_handler.show_source_gdb(None, symbol.symtab, - symbol.symtab.fullname(), - symbol.line) + raise gdb.GdbError( + "symbol " + arg + " does not seem to have an associated file" + ) + gui.source.lru_handler.show_source_gdb( + None, symbol.symtab, symbol.symtab.fullname(), symbol.line + ) + class GuiLogWindowCommand(gdb.Command): """Create a new log window. -Usage: gui log -This creates a new "log" window in the GUI. A log window is used -to display output from "gui print", "gui printf", "gui output", -and "gui dprintf". + Usage: gui log + This creates a new "log" window in the GUI. A log window is used + to display output from "gui print", "gui printf", "gui output", + and "gui dprintf". -Multiple log windows can be created and output can be directed to -a given instance using the "@" syntax, like: + Multiple log windows can be created and output can be directed to + a given instance using the "@" syntax, like: -gui print @5 variable""" + gui print @5 variable""" def __init__(self): - super(GuiLogWindowCommand, self).__init__('gui log', - gdb.COMMAND_SUPPORT) + super(GuiLogWindowCommand, self).__init__("gui log", gdb.COMMAND_SUPPORT) def invoke(self, arg, from_tty): self.dont_repeat() window = gui.logwindow.LogWindow() print("Created log window %d; now the default" % window.number) + class GuiPrintBase(gdb.Command): def __init__(self, command): - super(GuiPrintBase, self).__init__('gui ' + command, - gdb.COMMAND_SUPPORT) + super(GuiPrintBase, self).__init__("gui " + command, gdb.COMMAND_SUPPORT) self.command = command # Given ARG, return a pair (WINDOW, NEW_ARG). - def _parse_arg(self, arg, do_default = True): + def _parse_arg(self, arg, do_default=True): arg = arg.strip() - match = re.match('@(\\d+)\\s+(.*)$', arg) + match = re.match("@(\\d+)\\s+(.*)$", arg) if match is not None: winno = int(match.group(1)) arg = match.group(2) window = gui.toplevel.state.get(winno) if window is None: - raise gdb.GdbError('could not find window %d' % winno) + raise gdb.GdbError("could not find window %d" % winno) if not isinstance(window, gui.logwindow.LogWindow): - raise gdb.GdbError('window %d is not a log window' % winno) + raise gdb.GdbError("window %d is not a log window" % winno) elif do_default: window = gui.logwindow.default_log_window if window is None: - raise gdb.GdbError('no default log window') + raise gdb.GdbError("no default log window") else: window = None return (window, arg) def invoke(self, arg, from_tty): (window, arg) = self._parse_arg(arg) - text = gdb.execute(self.command + ' ' + arg, from_tty, True) + text = gdb.execute(self.command + " " + arg, from_tty, True) window.append(text) + class GuiPrintCommand(GuiPrintBase): """Print to a gui log window. -Usage: gui print [@N] ARGS -This is a wrapper for the "print" command that redirects its output -to a "gui log" window. If "@N" is given, then output goes to that -window; otherwise, output goes to the most recently created log window.""" + Usage: gui print [@N] ARGS + This is a wrapper for the "print" command that redirects its output + to a "gui log" window. If "@N" is given, then output goes to that + window; otherwise, output goes to the most recently created log window.""" + def __init__(self): - super(GuiPrintCommand, self).__init__('print') + super(GuiPrintCommand, self).__init__("print") + class GuiOutputCommand(GuiPrintBase): """Output to a gui log window. -Usage: gui output [@N] ARGS -This is a wrapper for the "output" command that redirects its output -to a "gui log" window. If "@N" is given, then output goes to that -window; otherwise, output goes to the most recently created log window.""" + Usage: gui output [@N] ARGS + This is a wrapper for the "output" command that redirects its output + to a "gui log" window. If "@N" is given, then output goes to that + window; otherwise, output goes to the most recently created log window.""" + def __init__(self): - super(GuiOutputCommand, self).__init__('output') + super(GuiOutputCommand, self).__init__("output") + class GuiPrintfCommand(GuiPrintBase): """printf to a gui log window. -Usage: gui printf [@N] ARGS -This is a wrapper for the "printf" command that redirects its output -to a "gui log" window. If "@N" is given, then output goes to that -window; otherwise, output goes to the most recently created log window.""" + Usage: gui printf [@N] ARGS + This is a wrapper for the "printf" command that redirects its output + to a "gui log" window. If "@N" is given, then output goes to that + window; otherwise, output goes to the most recently created log window.""" + def __init__(self): - super(GuiPrintfCommand, self).__init__('printf') + super(GuiPrintfCommand, self).__init__("printf") + class GuiDprintfCommand(GuiPrintBase): """dprintf to a gui log window. -Usage: gui dprintf [@N] ARGS -This is a wrapper for the "dprintf" command that redirects its output -to a "gui log" window. If "@N" is given, then output goes to that -window; otherwise, output goes to the most recently created log window.""" + Usage: gui dprintf [@N] ARGS + This is a wrapper for the "dprintf" command that redirects its output + to a "gui log" window. If "@N" is given, then output goes to that + window; otherwise, output goes to the most recently created log window.""" + def __init__(self): - super(GuiDprintfCommand, self).__init__('dprintf') + super(GuiDprintfCommand, self).__init__("dprintf") def invoke(self, arg, from_tty): (window, arg) = self._parse_arg(arg, False) @@ -216,29 +225,29 @@ window; otherwise, output goes to the most recently created log window.""" if arg is None: raise gdb.GdbError("no printf arguments to 'gui dprintf'") arg = arg.strip() - if not arg.startswith(','): + if not arg.startswith(","): raise gdb.GdbError("comma expected after linespec") arg = arg[1:] spec = arg[0 : -len(arg)] DPrintfBreakpoint(spec, window, arg) + class GuiDisplayCommand(gdb.Command): """Create a new display window. -Usage: gui display [-diff] COMMAND + Usage: gui display [-diff] COMMAND -A display window runs a gdb command after operations that change the -current frame or that cause the inferior to stop. If "-diff" is -given, then every time the display is updated, changed lines are -highlighted.""" + A display window runs a gdb command after operations that change the + current frame or that cause the inferior to stop. If "-diff" is + given, then every time the display is updated, changed lines are + highlighted.""" def __init__(self): - super(GuiDisplayCommand, self).__init__('gui display', - gdb.COMMAND_SUPPORT) + super(GuiDisplayCommand, self).__init__("gui display", gdb.COMMAND_SUPPORT) def invoke(self, arg, from_tty): self.dont_repeat() diff = False - if arg.startswith('-diff '): + if arg.startswith("-diff "): diff = True arg = arg[6:] gui.display.DisplayWindow(arg, diff) @@ -248,31 +257,31 @@ highlighted.""" # https://sourceware.org/bugzilla/show_bug.cgi?id=13077 return None + class InfoWindowsCommand(gdb.Command): """List all the GUI windows. -Usage: info windows -This lists all the GUI windows. -Note that this should not be confused with "info win", which is -part of the TUI.""" + Usage: info windows + This lists all the GUI windows. + Note that this should not be confused with "info win", which is + part of the TUI.""" def __init__(self): - super(InfoWindowsCommand, self).__init__('info windows', - gdb.COMMAND_SUPPORT) + super(InfoWindowsCommand, self).__init__("info windows", gdb.COMMAND_SUPPORT) def invoke(self, arg, from_tty): self.dont_repeat() gui.toplevel.state.display() + class DeleteWindowsCommand(gdb.Command): """Delete a GUI window. -Usage: delete window N -Delete GUI window number N. -A window's number appears in its title bar, and can also be -found using "info windows".""" + Usage: delete window N + Delete GUI window number N. + A window's number appears in its title bar, and can also be + found using "info windows".""" def __init__(self): - super(DeleteWindowsCommand, self).__init__('delete window', - gdb.COMMAND_SUPPORT) + super(DeleteWindowsCommand, self).__init__("delete window", gdb.COMMAND_SUPPORT) def invoke(self, arg, from_tty): self.dont_repeat() @@ -281,6 +290,7 @@ found using "info windows".""" if window is not None: window.destroy() + GuiCommand() GuiSourceCommand() GuiStackCommand() @@ -304,7 +314,7 @@ class TestCommand(gdb.Command): your copy of gdb has some command-overriding support.""" def __init__(self, set_it): - super(TestCommand, self).__init__('maint gui-test', gdb.COMMAND_DATA) + super(TestCommand, self).__init__("maint gui-test", gdb.COMMAND_DATA) self.set_it = set_it def invoke(self, arg, from_tty): @@ -317,13 +327,15 @@ class TestCommand(gdb.Command): except: pass + TestCommand(True) -TestCommand(False).invoke('', 0) +TestCommand(False).invoke("", 0) # See framecache.py - we prefer the before_prompt event if it exists; # but otherwise try the overriding approach. Both of these rely on a # hacked gdb :-( -if _can_override and not hasattr(gdb.events, 'before_prompt'): +if _can_override and not hasattr(gdb.events, "before_prompt"): + class Overrider(gdb.Command): def __init__(self, name, event): super(Overrider, self).__init__(name, gdb.COMMAND_DATA) @@ -333,6 +345,6 @@ if _can_override and not hasattr(gdb.events, 'before_prompt'): super(Overrider, self).invoke(arg, from_tty) self.event.post() - Overrider('up', gui.events.frame_changed) - Overrider('down', gui.events.frame_changed) - Overrider('frame', gui.events.frame_changed) + Overrider("up", gui.events.frame_changed) + Overrider("down", gui.events.frame_changed) + Overrider("frame", gui.events.frame_changed) diff --git a/gui/display.py b/gui/display.py index cc09879..b389fe2 100644 --- a/gui/display.py +++ b/gui/display.py @@ -27,38 +27,38 @@ from difflib import SequenceMatcher, Differ # FIXME: TO DO: # * highlight the changes + class DisplayWindow(gui.updatewindow.UpdateWindow): - def __init__(self, command, diff = False): + def __init__(self, command, diff=False): self.command = command self.diff = diff self.last_text = None - super(DisplayWindow, self).__init__('display') + super(DisplayWindow, self).__init__("display") @in_gdb_thread def on_event(self): try: - text = gdb.execute(self.command, to_string = True) + text = gdb.execute(self.command, to_string=True) except gdb.error as what: text = str(what) gui.startup.send_to_gtk(lambda: self._update(text)) @in_gtk_thread def gtk_initialize(self): - builder = gui.startup.create_builder('logwindow.xml') + builder = gui.startup.create_builder("logwindow.xml") builder.connect_signals(self) - self.window = builder.get_object('logwindow') - self.view = builder.get_object('textview') - self.view.modify_font(Pango.FontDescription('Fixed')) + self.window = builder.get_object("logwindow") + self.view = builder.get_object("textview") + self.view.modify_font(Pango.FontDescription("Fixed")) - self.buffer = builder.get_object('buffer') + self.buffer = builder.get_object("buffer") if self.diff: - self.tag = self.buffer.create_tag('new', foreground = 'red') + self.tag = self.buffer.create_tag("new", foreground="red") def _update(self, text): - self.buffer.delete(self.buffer.get_start_iter(), - self.buffer.get_end_iter()) + self.buffer.delete(self.buffer.get_start_iter(), self.buffer.get_end_iter()) if self.diff: if self.last_text is None: self.last_text = text.splitlines(1) @@ -67,14 +67,13 @@ class DisplayWindow(gui.updatewindow.UpdateWindow): split = text.splitlines(1) d = Differ() for line in d.compare(self.last_text, split): - if line[0] == ' ': - self.buffer.insert(self.buffer.get_end_iter(), - line[2:]) - elif line[0] == '+': - self.buffer.insert_with_tags(self.buffer.get_end_iter(), - line[2:], - self.tag) - self.buffer.insert(self.buffer.get_end_iter(), '\n') + if line[0] == " ": + self.buffer.insert(self.buffer.get_end_iter(), line[2:]) + elif line[0] == "+": + self.buffer.insert_with_tags( + self.buffer.get_end_iter(), line[2:], self.tag + ) + self.buffer.insert(self.buffer.get_end_iter(), "\n") self.last_text = split return self.buffer.insert_at_cursor(text) diff --git a/gui/dprintf.py b/gui/dprintf.py index d916d00..9f01412 100644 --- a/gui/dprintf.py +++ b/gui/dprintf.py @@ -19,12 +19,13 @@ import gdb import gui.logwindow from gui.startup import in_gdb_thread + class DPrintfBreakpoint(gdb.Breakpoint): @in_gdb_thread def __init__(self, spec, window, arg): super(DPrintfBreakpoint, self).__init__(spec, gdb.BP_BREAKPOINT) self.window = window - self.command = 'printf ' + arg + self.command = "printf " + arg @in_gdb_thread def stop(self): diff --git a/gui/events.py b/gui/events.py index e88816e..2d95bd6 100644 --- a/gui/events.py +++ b/gui/events.py @@ -15,6 +15,7 @@ import gdb + class _Event(object): def __init__(self): self.funcs = [] @@ -29,5 +30,6 @@ class _Event(object): for fun in self.funcs: fun(*args, **kwargs) + frame_changed = _Event() location_changed = _Event() diff --git a/gui/framecache.py b/gui/framecache.py index ad40503..5f5ea57 100644 --- a/gui/framecache.py +++ b/gui/framecache.py @@ -22,6 +22,7 @@ from gui.startup import in_gdb_thread _last_selected_frame = None + def check_frame(): global _last_selected_frame sel = None @@ -33,6 +34,7 @@ def check_frame(): _last_selected_frame = sel gui.events.frame_changed.post() + # We need this because we rely on the before_prompt hook to notify us # of frame changes. A dedicated frame change hook would be better. class FrameCommandInvoker(gui.invoker.Invoker): @@ -41,8 +43,9 @@ class FrameCommandInvoker(gui.invoker.Invoker): gui.invoker.Invoker.do_call(self) check_frame() + # See my gdb branch on github. -if hasattr(gdb.events, 'before_prompt'): +if hasattr(gdb.events, "before_prompt"): gdb.events.before_prompt.connect(check_frame) else: gui.adapt.notify_bug(13598) diff --git a/gui/gdbutil.py b/gui/gdbutil.py index 6e38c88..2ba7a3a 100644 --- a/gui/gdbutil.py +++ b/gui/gdbutil.py @@ -24,16 +24,18 @@ gui_prompt_substitutions = dict(gdb.prompt.prompt_substitutions) _current_window_for_prompt = None + def _prompt_window(attr): if _current_window_for_prompt is None: - return '' + return "" if attr is None: - return '' + return "" if not hasattr(_current_window_for_prompt, attr): return None return str(getattr(_current_window_for_prompt, attr)) -gui_prompt_substitutions['W'] = _prompt_window + +gui_prompt_substitutions["W"] = _prompt_window # GDB's API should do this... def substitute_prompt_with_window(prompt, window): @@ -49,6 +51,7 @@ def substitute_prompt_with_window(prompt, window): _current_window_for_prompt = None return result + # GDB's API should do this... def prompt_help_with_window(window): global _current_window_for_prompt @@ -63,6 +66,7 @@ def prompt_help_with_window(window): _current_window_for_prompt = None return result + @in_gdb_thread def is_running(): """Return True if the inferior is running.""" diff --git a/gui/invoker.py b/gui/invoker.py index 27f3f17..a5ac051 100644 --- a/gui/invoker.py +++ b/gui/invoker.py @@ -16,6 +16,7 @@ import gdb from gui.startup import in_gdb_thread + class Invoker(object): """A simple class that can invoke a gdb command. This is suitable for use as an event handler in Gtk.""" @@ -26,7 +27,7 @@ class Invoker(object): # This is invoked in the gdb thread to run the command. @in_gdb_thread def do_call(self): - gdb.execute(self.cmd, from_tty = True, to_string = True) + gdb.execute(self.cmd, from_tty=True, to_string=True) # The object itself is the Gtk event handler -- though really this # can be run in any thread. diff --git a/gui/logwindow.py b/gui/logwindow.py index 43ea1c2..5e3c5c6 100644 --- a/gui/logwindow.py +++ b/gui/logwindow.py @@ -25,25 +25,26 @@ from gui.startup import in_gtk_thread default_log_window = None + class LogWindow(gui.toplevel.Toplevel): def __init__(self): global default_log_window if default_log_window is not None: - default_log_window.default = '' + default_log_window.default = "" default_log_window = self # For the window title. - self.default = ' [Default]' - super(LogWindow, self).__init__('log') + self.default = " [Default]" + super(LogWindow, self).__init__("log") @in_gtk_thread def gtk_initialize(self): - builder = gui.startup.create_builder('logwindow.xml') + builder = gui.startup.create_builder("logwindow.xml") builder.connect_signals(self) - self.window = builder.get_object('logwindow') - self.view = builder.get_object('textview') + self.window = builder.get_object("logwindow") + self.view = builder.get_object("textview") self.view.modify_font(gui.params.font_manager.get_font()) - self.buffer = builder.get_object('buffer') + self.buffer = builder.get_object("buffer") @in_gtk_thread def set_font(self, font): @@ -56,7 +57,7 @@ class LogWindow(gui.toplevel.Toplevel): for window in gui.toplevel.state.windows(): if isinstance(window, LogWindow): default_log_window = window - window.default = ' [Default]' + window.default = " [Default]" window.update_title() break diff --git a/gui/notify.py b/gui/notify.py index 1cbdb9b..9e6e262 100644 --- a/gui/notify.py +++ b/gui/notify.py @@ -27,6 +27,7 @@ _initialized = False _last_time = None + @in_gtk_thread def _show_notification(title, content): global _initialized @@ -36,41 +37,45 @@ def _show_notification(title, content): n = Notify.Notification.new(title, content) n.show() + @in_gdb_thread def _on_stop(event): global _last_time t = _last_time _last_time = None - if (t is None + if ( + t is None or not gui.params.stop_notification.value - or time.process_time() - t < gui.params.stop_notification_seconds.value): + or time.process_time() - t < gui.params.stop_notification_seconds.value + ): return if isinstance(event, gdb.ExitedEvent): - title = 'gdb - inferior exited' - if hasattr(event, 'exit_code'): - content = 'inferior exited with code ' + str(event.exit_code) + title = "gdb - inferior exited" + if hasattr(event, "exit_code"): + content = "inferior exited with code " + str(event.exit_code) else: - content = 'inferior exited, code unavailable' + content = "inferior exited, code unavailable" elif isinstance(event, gdb.BreakpointEvent): - title = 'gdb - inferior stopped' - content = ('inferior stopped at breakpoint ' - + str(event.breakpoints[0].number)) + title = "gdb - inferior stopped" + content = "inferior stopped at breakpoint " + str(event.breakpoints[0].number) elif isinstance(event, gdb.SignalEvent): - title = 'gdb - inferior stopped' - content = 'inferior stopped with signal: ' + event.stop_signal + title = "gdb - inferior stopped" + content = "inferior stopped with signal: " + event.stop_signal else: - title = 'gdb - inferior stopped' - content = 'inferior stopped, reason unknown' + title = "gdb - inferior stopped" + content = "inferior stopped, reason unknown" gui.startup.send_to_gtk(lambda: _show_notification(title, content)) + @in_gdb_thread def _on_cont(event): global _last_time _last_time = time.process_time() + gdb.events.stop.connect(_on_stop) gdb.events.cont.connect(_on_cont) gdb.events.exited.connect(_on_stop) diff --git a/gui/params.py b/gui/params.py index 6f43c03..a9bdd79 100644 --- a/gui/params.py +++ b/gui/params.py @@ -24,33 +24,38 @@ import gui.toplevel from gui.startup import in_gdb_thread, in_gtk_thread from gi.repository import GtkSource, Pango + class _SetBase(gdb.Command): """Generic command for modifying GUI settings.""" def __init__(self): - super(_SetBase, self).__init__('set gui', gdb.COMMAND_NONE, - prefix = True) + super(_SetBase, self).__init__("set gui", gdb.COMMAND_NONE, prefix=True) + class _SetTitleBase(gdb.Command): """Generic command for modifying GUI window titles.""" def __init__(self): - super(_SetTitleBase, self).__init__('set gui title', gdb.COMMAND_NONE, - prefix = True) + super(_SetTitleBase, self).__init__( + "set gui title", gdb.COMMAND_NONE, prefix=True + ) + class _ShowBase(gdb.Command): """Generic command for showing GUI settings.""" def __init__(self): - super(_ShowBase, self).__init__('show gui', gdb.COMMAND_NONE, - prefix = True) + super(_ShowBase, self).__init__("show gui", gdb.COMMAND_NONE, prefix=True) + class _ShowTitleBase(gdb.Command): """Generic command for showing GUI window titles.""" def __init__(self): - super(_ShowTitleBase, self).__init__('show gui title', gdb.COMMAND_NONE, - prefix = True) + super(_ShowTitleBase, self).__init__( + "show gui title", gdb.COMMAND_NONE, prefix=True + ) + # Like gdb.Parameter, but has a default and automatically handles # storage. @@ -58,11 +63,10 @@ class _StoredParameter(gdb.Parameter): # NAME_FORMAT is like "%s" - NAME is substituted. # To construct the parameter name, "gui " is prefixed. def __init__(self, name_format, name, default, c_class, p_kind, *args): - full_name = 'gui ' + name_format % name - self.storage_name = '-'.join((name_format % name).split(' ')) + full_name = "gui " + name_format % name + self.storage_name = "-".join((name_format % name).split(" ")) storage = gui.storage.storage_manager - super(_StoredParameter, self).__init__(full_name, c_class, p_kind, - *args) + super(_StoredParameter, self).__init__(full_name, c_class, p_kind, *args) if p_kind is gdb.PARAM_BOOLEAN: val = storage.getboolean(self.storage_name) elif p_kind is gdb.PARAM_STRING or p_kind is gdb.PARAM_ENUM: @@ -87,19 +91,25 @@ class _StoredParameter(gdb.Parameter): self.storage.set(self.storage_name, self.value) return "" + class _Theme(_StoredParameter): # Silly gdb requirement. - "" + """""" set_doc = "Set the source window theme." show_doc = "Show the source window theme." def __init__(self): self.manager = GtkSource.StyleSchemeManager.get_default() - super(_Theme, self).__init__('%s', 'theme', None, - gdb.COMMAND_NONE, gdb.PARAM_ENUM, - # Probably the wrong thread. - self.manager.get_scheme_ids()) + super(_Theme, self).__init__( + "%s", + "theme", + None, + gdb.COMMAND_NONE, + gdb.PARAM_ENUM, + # Probably the wrong thread. + self.manager.get_scheme_ids(), + ) @in_gdb_thread def set_buffer_manager(self, b): @@ -120,17 +130,19 @@ class _Theme(_StoredParameter): self.buffer_manager.change_theme() return "" + class _Font(_StoredParameter): # Silly gdb requirement. - "" + """""" set_doc = "Set the source window font." show_doc = "Show the source window font." def __init__(self): self.manager = GtkSource.StyleSchemeManager.get_default() - super(_Font, self).__init__('%s', 'font', 'monospace', - gdb.COMMAND_NONE, gdb.PARAM_STRING) + super(_Font, self).__init__( + "%s", "font", "monospace", gdb.COMMAND_NONE, gdb.PARAM_STRING + ) @in_gtk_thread def get_font(self): @@ -147,11 +159,13 @@ class _Font(_StoredParameter): super(_Font, self).get_set_string() return "" + title_params = {} + class _Title(_StoredParameter): # Silly gdb requirement. - "" + """""" def __init__(self, name, default): title_params[name] = self @@ -159,9 +173,10 @@ class _Title(_StoredParameter): self.set_doc = "Set the %s window title format." % self.name self.show_doc = "Show the %s window title format." % self.name self.manager = GtkSource.StyleSchemeManager.get_default() - super(_Title, self).__init__('title %s', name, default, - gdb.COMMAND_NONE, gdb.PARAM_STRING) - val = self.storage.get('title-%s' % name) + super(_Title, self).__init__( + "title %s", name, default, gdb.COMMAND_NONE, gdb.PARAM_STRING + ) + val = self.storage.get("title-%s" % name) if val is not None: self.value = val else: @@ -169,8 +184,7 @@ class _Title(_StoredParameter): @in_gdb_thread def get_show_string(self, pvalue): - return "The current title format for the %s is: %s" % (self.name, - self.value) + return "The current title format for the %s is: %s" % (self.name, self.value) @in_gdb_thread def get_set_string(self): @@ -178,16 +192,18 @@ class _Title(_StoredParameter): gui.toplevel.state.update_titles() return "" + class _Missing(_StoredParameter): # Silly gdb requirement. - "" + """""" set_doc = "Set whether to mention missing gdb features." show_doc = "Show whether to mention missing gdb features." def __init__(self): - super(_Missing, self).__init__('%s', 'mention-missing', True, - gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN) + super(_Missing, self).__init__( + "%s", "mention-missing", True, gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN + ) @in_gdb_thread def get_show_string(self, pvalue): @@ -197,21 +213,22 @@ class _Missing(_StoredParameter): v = "off" return "Whether to warn about missing gdb features: " + v + class _Lines(_StoredParameter): # Silly gdb requirement. - "" + """""" set_doc = "Set whether to display line numbers in the source window." show_doc = "Show whether to display line numbers in the source window." def __init__(self): - super(_Lines, self).__init__('%s', 'line-numbers', False, - gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN) + super(_Lines, self).__init__( + "%s", "line-numbers", False, gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN + ) @in_gdb_thread def get_show_string(self, pvalue): - return "The current title format for the %s is: %s" % (self.name, - self.value) + return "The current title format for the %s is: %s" % (self.name, self.value) @in_gdb_thread def get_set_string(self): @@ -219,20 +236,24 @@ class _Lines(_StoredParameter): gui.toplevel.state.set_line_numbers(self.value) return "" + class _Lines(_StoredParameter): # Silly gdb requirement. - "" + """""" set_doc = "Set whether to display line numbers in the source window." show_doc = "Show whether to display line numbers in the source window." def __init__(self): - super(_Lines, self).__init__('%s', 'line-numbers', False, - gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN) + super(_Lines, self).__init__( + "%s", "line-numbers", False, gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN + ) @in_gdb_thread def get_show_string(self, pvalue): - return "Whether to display line numbers in the source window is: %s" % self.value + return ( + "Whether to display line numbers in the source window is: %s" % self.value + ) @in_gdb_thread def get_set_string(self): @@ -240,16 +261,18 @@ class _Lines(_StoredParameter): gui.toplevel.state.set_line_numbers(self.value) return "" + class _Tabs(_StoredParameter): # Silly gdb requirement. - "" + """""" set_doc = "Set width of tabs in the source window." show_doc = "Show width of tabs in the source window." def __init__(self): - super(_Tabs, self).__init__('%s', 'tab-width', 8, - gdb.COMMAND_NONE, gdb.PARAM_ZINTEGER) + super(_Tabs, self).__init__( + "%s", "tab-width", 8, gdb.COMMAND_NONE, gdb.PARAM_ZINTEGER + ) @in_gdb_thread def get_show_string(self, pvalue): @@ -261,40 +284,45 @@ class _Tabs(_StoredParameter): gui.toplevel.state.set_tab_width(self.value) return "" + class _StopNotification(_StoredParameter): # Silly gdb requirement. - "" + """""" set_doc = "Set whether stop notifications are displayed." show_doc = "Show whether stop notifications are displayed." def __init__(self): - super(_StopNotification, self).__init__('%s', 'stop-notification', True, - gdb.COMMAND_RUNNING, - gdb.PARAM_BOOLEAN) + super(_StopNotification, self).__init__( + "%s", "stop-notification", True, gdb.COMMAND_RUNNING, gdb.PARAM_BOOLEAN + ) @in_gdb_thread def get_show_string(self, pvalue): return "Whether stop notifications are displayed is: %s" % self.value + class _StopNotificationSeconds(_StoredParameter): # Silly gdb requirement. - "" + """""" set_doc = "Set stop notification timeout in seconds." show_doc = "Show stop notification timeout." def __init__(self): - super(_StopNotificationSeconds, self).__init__('%s', - 'stop-notification-seconds', - 120, - gdb.COMMAND_RUNNING, - gdb.PARAM_ZINTEGER) + super(_StopNotificationSeconds, self).__init__( + "%s", + "stop-notification-seconds", + 120, + gdb.COMMAND_RUNNING, + gdb.PARAM_ZINTEGER, + ) @in_gdb_thread def get_show_string(self, pvalue): return "Stop notifications are displayed after %d seconds." % self.value + _SetBase() _SetTitleBase() _ShowBase() @@ -304,10 +332,10 @@ font_manager = _Font() stop_notification = _StopNotification() stop_notification_seconds = _StopNotificationSeconds() -_Title('source', '\\W{basename} [GDB Source @\\W{number}]') -_Title('display', '\\W{command} [GDB Display @\\W{number}]') -_Title('log', '[GDB Log @\\W{number}]\\W{default}') -_Title('stack', '[GDB Stack @\\W{number}]') +_Title("source", "\\W{basename} [GDB Source @\\W{number}]") +_Title("display", "\\W{command} [GDB Display @\\W{number}]") +_Title("log", "[GDB Log @\\W{number}]\\W{default}") +_Title("stack", "[GDB Stack @\\W{number}]") warn_missing = _Missing() line_numbers = _Lines() diff --git a/gui/source.py b/gui/source.py index 0c255a7..a38a9ea 100644 --- a/gui/source.py +++ b/gui/source.py @@ -31,6 +31,7 @@ import gui.bpcache from gi.repository import Gtk, GtkSource, GObject, Gdk, GdkPixbuf, Pango + class BufferManager: def __init__(self): self.buffers = {} @@ -38,7 +39,7 @@ class BufferManager: gui.params.source_theme.set_buffer_manager(self) gui.events.location_changed.connect(self._location_changed) # FIXME - emit a warning if this isn't available. - if hasattr(gdb.events, 'clear_objfiles'): + if hasattr(gdb.events, "clear_objfiles"): gdb.events.clear_objfiles.connect(self._clear_objfiles) self.empty_buffer = None @@ -60,13 +61,13 @@ class BufferManager: while True: line = iter.get_line() + 1 if line in line_set: - buffer.create_source_mark(None, 'executable', iter) + buffer.create_source_mark(None, "executable", iter) if not iter.forward_line(): break @in_gdb_thread def _get_lines_update(self, buffer, symtab): - if hasattr(symtab, 'linetable'): + if hasattr(symtab, "linetable"): line_set = set(symtab.linetable().source_lines()) gui.startup.send_to_gtk(lambda: self._set_marks(buffer, line_set)) @@ -113,9 +114,9 @@ class BufferManager: @in_gtk_thread def update_breakpoint_location(self, sal, is_set): if is_set: - category = 'breakpoint' + category = "breakpoint" else: - category = 'executable' + category = "executable" [fullname, line] = sal if fullname in self.buffers: buffer = self.buffers[fullname] @@ -125,8 +126,7 @@ class BufferManager: @in_gdb_thread def _location_changed(self, loc, is_set): - gui.startup.send_to_gtk(lambda: self.update_breakpoint_location(loc, - is_set)) + gui.startup.send_to_gtk(lambda: self.update_breakpoint_location(loc, is_set)) @in_gtk_thread def _gtk_clear_objfiles(self): @@ -144,9 +144,10 @@ class BufferManager: for key in self.buffers: buff = self.buffers[key] # This could probably be more efficient. - buff.remove_source_marks(buff.get_start_iter(), - buff.get_end_iter(), - 'pointer') + buff.remove_source_marks( + buff.get_start_iter(), buff.get_end_iter(), "pointer" + ) + buffer_manager = BufferManager() @@ -168,7 +169,7 @@ def get_current_location(): # No frame - try 'main'. try: frame = None - sym = gdb.lookup_global_symbol('main') + sym = gdb.lookup_global_symbol("main") lineno = sym.line symtab = sym.symtab filename = symtab.fullname() @@ -179,6 +180,7 @@ def get_current_location(): return (None, None, None, None) return (frame, symtab, filename, lineno) + class LRUHandler: def __init__(self): self.windows = [] @@ -190,10 +192,9 @@ class LRUHandler: if len(self.windows) == 0: self.work_location = (frame, symtab, srcfile, srcline) SourceWindow() - gui.startup.send_to_gtk(lambda: self.show_source(frame, - symtab, - srcfile, - srcline)) + gui.startup.send_to_gtk( + lambda: self.show_source(frame, symtab, srcfile, srcline) + ) @in_gdb_thread def new_source_window(self): @@ -204,16 +205,15 @@ class LRUHandler: def on_event(self, *args): (frame, symtab, filename, lineno) = get_current_location() if filename is not None: - gui.startup.send_to_gtk(lambda: self.show_source(frame, - symtab, - filename, - lineno)) + gui.startup.send_to_gtk( + lambda: self.show_source(frame, symtab, filename, lineno) + ) @in_gdb_thread def _connect_events(self): gdb.events.stop.connect(self.on_event) gui.events.frame_changed.connect(self.on_event) - if hasattr(gdb.events, 'new_objfile'): + if hasattr(gdb.events, "new_objfile"): gdb.events.new_objfile.connect(self._new_objfile) @in_gdb_thread @@ -263,27 +263,28 @@ class LRUHandler: if self.work_location is not None: (frame, symtab, filename, lineno) = self.work_location self.work_location = None - gui.startup.send_to_gtk(lambda: self.show_source(frame, - symtab, - filename, - lineno)) + gui.startup.send_to_gtk( + lambda: self.show_source(frame, symtab, filename, lineno) + ) @in_gdb_thread def _new_objfile(self, event): if len(gdb.objfiles()) == 1: self.on_event() + lru_handler = LRUHandler() BUTTON_NAMES = ["step", "next", "continue", "finish", "stop", "up", "down"] + class SourceWindow(gui.updatewindow.UpdateWindow): def _get_pixmap(self, filename): path = os.path.join(gui.self_dir, filename) return GdkPixbuf.Pixbuf.new_from_file(path) def __init__(self): - super(SourceWindow, self).__init__('source') + super(SourceWindow, self).__init__("source") gdb.events.cont.connect(self._on_cont_event) # Update the buttons. self.on_event() @@ -300,7 +301,7 @@ class SourceWindow(gui.updatewindow.UpdateWindow): self.do_up = FrameCommandInvoker("up") self.do_down = FrameCommandInvoker("down") - builder = gui.startup.create_builder('sourcewindow.xml') + builder = gui.startup.create_builder("sourcewindow.xml") builder.connect_signals(self) self.window = builder.get_object("sourcewindow") self.view = builder.get_object("view") @@ -315,16 +316,16 @@ class SourceWindow(gui.updatewindow.UpdateWindow): self.view.set_tab_width(gui.params.tab_width.value) attrs = GtkSource.MarkAttributes() - attrs.set_pixbuf(self._get_pixmap('icons/ok.png')) - self.view.set_mark_attributes('executable', attrs, 0) + attrs.set_pixbuf(self._get_pixmap("icons/ok.png")) + self.view.set_mark_attributes("executable", attrs, 0) attrs = GtkSource.MarkAttributes() - attrs.set_pixbuf(self._get_pixmap('icons/breakpoint-marker.png')) - self.view.set_mark_attributes('breakpoint', attrs, 1) + attrs.set_pixbuf(self._get_pixmap("icons/breakpoint-marker.png")) + self.view.set_mark_attributes("breakpoint", attrs, 1) attrs = GtkSource.MarkAttributes() - attrs.set_pixbuf(self._get_pixmap('icons/line-pointer.png')) - self.view.set_mark_attributes('pointer', attrs, 2) + attrs.set_pixbuf(self._get_pixmap("icons/line-pointer.png")) + self.view.set_mark_attributes("pointer", attrs, 2) self.view.set_buffer(buffer_manager.get_empty_buffer()) lru_handler.add(self) @@ -363,14 +364,14 @@ class SourceWindow(gui.updatewindow.UpdateWindow): filename = self.view.get_buffer().filename line = textiter.get_line() + 1 if gui.bpcache.any_breakpoint_at(filename, line): - fun = Invoker("clear %s:%d" % (filename,line)) + fun = Invoker("clear %s:%d" % (filename, line)) else: fun = Invoker("break %s:%d" % (filename, line)) fun() def _do_scroll(self, buff, srcline): iter = buff.get_iter_at_line(srcline) - buff.create_source_mark(None, 'pointer', iter) + buff.create_source_mark(None, "pointer", iter) buff.place_cursor(iter) self.view.scroll_mark_onscreen(buff.get_insert()) return False diff --git a/gui/stack.py b/gui/stack.py index 400c584..9f2374d 100644 --- a/gui/stack.py +++ b/gui/stack.py @@ -27,6 +27,7 @@ from gui.framecache import FrameCommandInvoker from gui.startup import in_gdb_thread, in_gtk_thread from gi.repository import Gtk + def format_frame(frame): result = {} result["name"] = frame.function() @@ -42,10 +43,11 @@ def format_frame(frame): return result # FIXME args + class StackWindow(gui.updatewindow.UpdateWindow): def __init__(self): self.raw = False - super(StackWindow, self).__init__('stack') + super(StackWindow, self).__init__("stack") # Connect events. # Update buttons. @@ -53,11 +55,11 @@ class StackWindow(gui.updatewindow.UpdateWindow): def gtk_initialize(self): self.do_up = FrameCommandInvoker("up") self.do_down = FrameCommandInvoker("down") - builder = gui.startup.create_builder('stackwindow.xml') + builder = gui.startup.create_builder("stackwindow.xml") builder.connect_signals(self) - self.window = builder.get_object('stackwindow') - self.view = builder.get_object('view') + self.window = builder.get_object("stackwindow") + self.view = builder.get_object("view") self.text = Gtk.TextBuffer() self.view.set_buffer(self.text) self.view.modify_font(gui.params.font_manager.get_font()) @@ -67,7 +69,7 @@ class StackWindow(gui.updatewindow.UpdateWindow): self.text.delete(self.text.get_start_iter(), self.text.get_end_iter()) frame_no = 1 for frame in data: - self.text.insert_at_cursor('#%d ' % frame_no) + self.text.insert_at_cursor("#%d " % frame_no) frame_no = frame_no + 1 # Goofball API. if isinstance(frame["name"], str): @@ -80,8 +82,9 @@ class StackWindow(gui.updatewindow.UpdateWindow): # FIXME args self.text.insert_at_cursor("\n") if frame["line"] is not None: - self.text.insert_at_cursor(" at %s:%d\n" % (frame["filename"], - frame["line"])) + self.text.insert_at_cursor( + " at %s:%d\n" % (frame["filename"], frame["line"]) + ) if frame["solib"] is not None: self.text.insert_at_cursor(" [%s]\n" % frame["solib"]) @@ -91,11 +94,12 @@ class StackWindow(gui.updatewindow.UpdateWindow): try: start_frame = gdb.newest_frame() if not self.raw: - frame_iter = gdb.frames.execute_frame_filters(start_frame, - 0, -1) + frame_iter = gdb.frames.execute_frame_filters(start_frame, 0, -1) if frame_iter is None: - frame_iter = map(gdb.FrameDecorator.FrameDecorator, - gdb.FrameIterator.FrameIterator(start_frame)) + frame_iter = map( + gdb.FrameDecorator.FrameDecorator, + gdb.FrameIterator.FrameIterator(start_frame), + ) data = list(map(format_frame, frame_iter)) except gdb.error: data = [] @@ -105,6 +109,7 @@ class StackWindow(gui.updatewindow.UpdateWindow): def set_font(self, pango_font): self.view.modify_font(pango_font) + def show_stack(): # for now StackWindow() diff --git a/gui/startup.py b/gui/startup.py index 8974664..8812c86 100644 --- a/gui/startup.py +++ b/gui/startup.py @@ -22,9 +22,9 @@ import gui import gi -gi.require_version('Gtk', '3.0') -gi.require_version('GtkSource', '3.0') -gi.require_version('Notify', '0.7') +gi.require_version("Gtk", "3.0") +gi.require_version("GtkSource", "3.0") +gi.require_version("Notify", "0.7") from gi.repository import Gtk, Gdk, GObject, GtkSource, GLib, GdkPixbuf @@ -32,11 +32,13 @@ from gi.repository import Gtk, Gdk, GObject, GtkSource, GLib, GdkPixbuf _event_queue = queue.Queue() + def send_to_gtk(func): _event_queue.put(func) # The payload is arbitrary. os.write(write_pipe, bytes(1)) + class _GtkThread(gdb.Thread): def handle_queue(self, source, condition): global _event_queue @@ -51,17 +53,19 @@ class _GtkThread(gdb.Thread): GObject.type_register(GtkSource.View) Gtk.main() + _gdb_thread = threading.current_thread() _t = None + def start_gtk(): global _t if _t is None: - GLib.set_application_name('GDB') - GLib.set_prgname('GDB') - Gdk.set_program_class('GDB') - Gtk.Window.set_default_icon_name('GDB') - path = os.path.join(gui.self_dir, 'icons/face-raspberry-symbolic.svg') + GLib.set_application_name("GDB") + GLib.set_prgname("GDB") + Gdk.set_program_class("GDB") + Gtk.Window.set_default_icon_name("GDB") + path = os.path.join(gui.self_dir, "icons/face-raspberry-symbolic.svg") Gtk.Window.set_default_icon(GdkPixbuf.Pixbuf.new_from_file(path)) GObject.threads_init() Gdk.threads_init() @@ -69,21 +73,26 @@ def start_gtk(): _t.setDaemon(True) _t.start() + def create_builder(filename): builder = Gtk.Builder() builder.add_from_file(os.path.join(gui.self_dir, filename)) return builder + def in_gdb_thread(func): def ensure_gdb_thread(*args, **kwargs): if threading.current_thread() is not _gdb_thread: raise RuntimeError("must run '%s' in gdb thread" % repr(func)) return func(*args, **kwargs) + return ensure_gdb_thread + def in_gtk_thread(func): def ensure_gtk_thread(*args, **kwargs): if threading.current_thread() is not _t: raise RuntimeError("must run '%s' in Gtk thread" % repr(func)) return func(*args, **kwargs) + return ensure_gtk_thread diff --git a/gui/storage.py b/gui/storage.py index bcf2bac..971057e 100644 --- a/gui/storage.py +++ b/gui/storage.py @@ -21,10 +21,11 @@ import errno import configparser import atexit + class StorageManager: def __init__(self): - self.dir = os.path.join(GLib.get_user_config_dir(), 'gdb') - self.file = os.path.join(self.dir, 'settings') + self.dir = os.path.join(GLib.get_user_config_dir(), "gdb") + self.file = os.path.join(self.dir, "settings") try: os.mkdir(self.dir, 0o700) except OSError as exc: @@ -33,30 +34,31 @@ class StorageManager: self.config = configparser.RawConfigParser() if self.file is not None: self.config.read(self.file) - if not self.config.has_section('general'): - self.config.add_section('general') + if not self.config.has_section("general"): + self.config.add_section("general") atexit.register(self.write) def get(self, name): - if self.config.has_option('general', name): - return self.config.get('general', name) + if self.config.has_option("general", name): + return self.config.get("general", name) return None def getboolean(self, name): - if self.config.has_option('general', name): - return self.config.getboolean('general', name) + if self.config.has_option("general", name): + return self.config.getboolean("general", name) return None def getint(self, name): - if self.config.has_option('general', name): - return self.config.getint('general', name) + if self.config.has_option("general", name): + return self.config.getint("general", name) return None def set(self, name, value): - self.config.set('general', name, value) + self.config.set("general", name, value) def write(self): - with open(self.file, 'wt') as save_file: + with open(self.file, "wt") as save_file: self.config.write(save_file) + storage_manager = StorageManager() diff --git a/gui/toplevel.py b/gui/toplevel.py index c720909..d413632 100644 --- a/gui/toplevel.py +++ b/gui/toplevel.py @@ -25,6 +25,7 @@ import threading from gi.repository import Pango from gui.startup import in_gdb_thread, in_gtk_thread + class _ToplevelState(object): def __init__(self): gui.startup.start_gtk() @@ -73,12 +74,11 @@ class _ToplevelState(object): print("No windows") return - print(' Num Name') + print(" Num Name") for winno in range(1, self.next_toplevel): if winno in self.toplevels: window = self.toplevels[winno] - print(' %3d %s' % (window.number, - window.window.get_title())) + print(" %3d %s" % (window.number, window.window.get_title())) @in_gtk_thread def _do_set_font(self, font_name): @@ -125,15 +125,17 @@ class _ToplevelState(object): def windows(self): return list(self.toplevels.values()) + state = _ToplevelState() + class Toplevel(object): def __init__(self, window_type): state.add(self, window_type) # The subclass must set this. self.window = None self.window_type = window_type - self.storage_name = window_type + '-' + str(self.type_number) + '-geom' + self.storage_name = window_type + "-" + str(self.type_number) + "-geom" gui.startup.send_to_gtk(self._do_gtk_initialize) @in_gtk_thread @@ -145,7 +147,7 @@ class Toplevel(object): @in_gtk_thread def _do_gtk_initialize(self): self.gtk_initialize() - self.window.connect('configure-event', self._on_resize) + self.window.connect("configure-event", self._on_resize) geom = gui.storage.storage_manager.get(self.storage_name) if geom: self.window.parse_geometry(geom) @@ -158,7 +160,7 @@ class Toplevel(object): @in_gtk_thread def _on_resize(self, widget, event): - geom = '%dx%d+%d+%d' % (event.width, event.height, event.x, event.y) + geom = "%dx%d+%d+%d" % (event.width, event.height, event.x, event.y) gdb.post_event(lambda: self._save_size(geom)) return False diff --git a/gui/updatewindow.py b/gui/updatewindow.py index 5a07e77..560e2e5 100644 --- a/gui/updatewindow.py +++ b/gui/updatewindow.py @@ -21,6 +21,7 @@ from gui.startup import in_gdb_thread, in_gtk_thread import gdb import gui.events + class UpdateWindow(Toplevel): """A window that automatically updates in response to gdb changes. diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..4469f1c --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,5 @@ +[tool.black] +include = "\\.py(\\.in)?$" + +[tool.pyright] +typeCheckingMode = "strict"