diff --git a/README b/README index 125187e..28e6e05 100644 --- a/README +++ b/README @@ -15,14 +15,14 @@ GUIs in a few ways: To get started, install the prerequisites. You'll need a -Python-enabled gdb, PyGtk, and PyGktSourceView. (And maybe more -- if -you trip across something, let me know.) You'll need the Python +Python-enabled gdb, PyGObject, and PyGktSourceView. (And maybe more +-- if you trip across something, let me know.) You'll need the Python development package to compile the small C module that is included here. On Fedora I think this suffices: - sudo yum install gdb python-devel pygtksourceview pygtk2 + sudo yum install gdb python-devel gtksourceview3 pygobject3 After you install this, type "make". Now, start gdb and source the "SourceMe.py" file. This sets everything up. @@ -31,3 +31,7 @@ This adds a new "gui" command to gdb. Currently the only subcommand is "gui source", which pops up a source window. The source window will automatically track your progress when debugging. You can make multiple source windows; they will be reused in an LRU fashion. + +If you want to hack on this, you will need Glade to edit the UI +elements. For Fedora 18, you'll need a special hack to make the +gtksourceview widget visible to Glade. diff --git a/gui/__init__.py b/gui/__init__.py index e69de29..73e0db8 100644 --- a/gui/__init__.py +++ b/gui/__init__.py @@ -0,0 +1,18 @@ +# Copyright (C) 2013 Tom Tromey + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import os.path + +self_dir = os.path.abspath(os.path.dirname(__file__)) diff --git a/gui/icons/README b/gui/icons/README new file mode 100644 index 0000000..6ad3eaf --- /dev/null +++ b/gui/icons/README @@ -0,0 +1 @@ +These icons were shamelessly taken from nemiver. diff --git a/gui/icons/breakpoint-disabled-marker.png b/gui/icons/breakpoint-disabled-marker.png new file mode 100644 index 0000000..569c982 Binary files /dev/null and b/gui/icons/breakpoint-disabled-marker.png differ diff --git a/gui/icons/breakpoint-marker.png b/gui/icons/breakpoint-marker.png new file mode 100644 index 0000000..70eb997 Binary files /dev/null and b/gui/icons/breakpoint-marker.png differ diff --git a/gui/icons/countpoint-marker.png b/gui/icons/countpoint-marker.png new file mode 100644 index 0000000..3700e55 Binary files /dev/null and b/gui/icons/countpoint-marker.png differ diff --git a/gui/icons/line-pointer.png b/gui/icons/line-pointer.png new file mode 100644 index 0000000..ca8d86d Binary files /dev/null and b/gui/icons/line-pointer.png differ diff --git a/gui/icons/run-to-cursor.xpm b/gui/icons/run-to-cursor.xpm new file mode 100644 index 0000000..16607e6 --- /dev/null +++ b/gui/icons/run-to-cursor.xpm @@ -0,0 +1,40 @@ +/* XPM */ +static char * run_to_cursor_xpm[] = { +"22 22 15 1", +" c None", +". c #4A4A4A", +"+ c #BABABA", +"@ c #C0C0C0", +"# c #9C9C9C", +"$ c #000000", +"% c #CCCCCC", +"& c #D4D4D4", +"* c #D7D7D8", +"= c #DCDCDC", +"- c #E3E3E3", +"; c #EBEBEB", +"> c #F4F3F3", +", c #FEFEFE", +"' c #B72618", +" ", +" ", +" ", +" ........... ", +" .++++++++@.# ", +" .+++++@@@@.## ", +" .++@@$$@%%.... ", +" .@@@%$$%&&*==. ", +" .%%%%$$&*==--. ", +" .%&&*$$=---;;. ", +" .&*==$$;;;;>;. ", +" .=-$$$$$$>>,,. ", +" .;;;$$$$>,,,,. ", +" .;;>>$$,,,,,,. ", +" .>'''''''''',. ", +" .,'''''''''',. ", +" .,,,,,,,,,,,,. ", +" .,,,,,,,,,,,,. ", +" .............. ", +" ", +" ", +" "}; diff --git a/gui/icons/set-breakpoint.xpm b/gui/icons/set-breakpoint.xpm new file mode 100644 index 0000000..f3141f9 --- /dev/null +++ b/gui/icons/set-breakpoint.xpm @@ -0,0 +1,52 @@ +/* XPM */ +static char * breakpoint_xpm[] = { +"22 22 27 1", +" c None", +". c #394248", +"+ c #B1B5B8", +"@ c #B6B9BC", +"# c #B8BBBE", +"$ c #C0C0C0", +"% c #C6C9CB", +"& c #CBCED0", +"* c #D1D3D5", +"= c #BBBEC1", +"- c #BDC1C3", +"; c #C3C7C8", +"> c #C9CBCD", +", c #D4D6D8", +"' c #D6D8DA", +") c #0C1115", +"! c #DADCDD", +"~ c #DEE0E1", +"{ c #E2E3E5", +"] c #E6E7E8", +"^ c #E7E8E9", +"/ c #EBECED", +"( c #FF0000", +"_ c #000000", +": c #F3F4F4", +"< c #F7F8F9", +"[ c #FDFDFD", +" ", +" ", +" ", +" ................ ", +" .++++++@#$$%%&*. ", +" .++++@#=-;%>&,'. ", +" .++))))))))))'!. ", +" .+@#=-;>&*,'!~{. ", +" .#=))))&,,!~{]^. ", +" .-;;;,,/////^//. ", +" .;(((((/)))__::. ", +" .>(((((/////:<[. ", +" .*(((((/))))<[[. ", +" .'(((((/:<<[[[[. ", +" .!(((((:_____[[. ", +" .{]/:::<[[[[[[[. ", +" .//))))))[[[[[[. ", +" .::<<[[[[[[[[[[. ", +" ................ ", +" ", +" ", +" "}; diff --git a/gui/icons/step-into.xpm b/gui/icons/step-into.xpm new file mode 100644 index 0000000..e168c80 --- /dev/null +++ b/gui/icons/step-into.xpm @@ -0,0 +1,28 @@ +/* XPM */ +static char * step_in_xpm[] = { +"22 22 3 1", +" c None", +". c #FF0000", +"+ c #000000", +" ", +" ", +" ", +" ", +" ......... ", +" ......... ", +" .. ", +" ++ .. ++ ", +" ++......++ ", +" ++ .... ++ ", +" ++ .. ++ ", +" ++ ++ ", +" ++ ++ ", +" ++ ++ ", +" ++ ++ ", +" ++ ++ ", +" ++ ++ ", +" ++ ++ ", +" ", +" ", +" ", +" "}; diff --git a/gui/icons/step-out.xpm b/gui/icons/step-out.xpm new file mode 100644 index 0000000..1f10cf6 --- /dev/null +++ b/gui/icons/step-out.xpm @@ -0,0 +1,28 @@ +/* XPM */ +static char * step_out_xpm[] = { +"22 22 3 1", +" c None", +". c #FF0000", +"+ c #000000", +" ", +" ", +" . ", +" .. ", +" ......... ", +" ......... ", +" .. .. ", +" ++ .. ++ . ", +" ++ .. ++ ", +" ++ .. ++ ", +" ++ .. ++ ", +" ++ ++ ", +" ++ ++ ", +" ++ ++ ", +" ++ ++ ", +" ++ ++ ", +" ++ ++ ", +" ++ ++ ", +" ", +" ", +" ", +" "}; diff --git a/gui/icons/step-over.xpm b/gui/icons/step-over.xpm new file mode 100644 index 0000000..5b68cc5 --- /dev/null +++ b/gui/icons/step-over.xpm @@ -0,0 +1,28 @@ +/* XPM */ +static char * step_over_xpm[] = { +"22 22 3 1", +" c None", +". c #FF0000", +"+ c #000000", +" ", +" ", +" ", +" . ", +" .. ", +" ................ ", +" ................ ", +" .. ", +" ++ ++ . ", +" ++ ++ ", +" ++ ++ ", +" ++ ++ ", +" ++ ++ ", +" ++ ++ ", +" ++ ++ ", +" ++ ++ ", +" ++ ++ ", +" ++ ++ ", +" ++ ++ ", +" ", +" ", +" "}; diff --git a/gui/icons/throbber.gif b/gui/icons/throbber.gif new file mode 100644 index 0000000..529e72f Binary files /dev/null and b/gui/icons/throbber.gif differ diff --git a/gui/invoker.py b/gui/invoker.py new file mode 100644 index 0000000..9fa21e8 --- /dev/null +++ b/gui/invoker.py @@ -0,0 +1,31 @@ +# Copyright (C) 2013 Tom Tromey + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import gdb + +class Invoker(object): + """A simple class that can invoke a gdb command. + This is suitable for use as an event handler in Gtk.""" + + def __init__(self, cmd): + self.cmd = cmd + + # This is invoked in the gdb thread to run the command. + def do_call(self): + gdb.execute(self.cmd, from_tty = True, to_string = True) + + # The object itself is the Gtk event handler. + def __call__(self, *args): + gdb.post_event(self.do_call) diff --git a/gui/source.py b/gui/source.py index d8bf176..9f9e7f8 100644 --- a/gui/source.py +++ b/gui/source.py @@ -16,9 +16,11 @@ # Source view. import gdb +from gui.invoker import Invoker import gui.startup -import gtksourceview2 as gtksourceview -import gtk +import os.path + +from gi.repository import Gtk, GtkSource, GObject class BufferManager: def __init__(self): @@ -32,7 +34,7 @@ class BufferManager: if filename in self.buffers: return self.buffers[filename] - buff = gtksourceview.Buffer() + buff = GtkSource.Buffer() buff.begin_not_undoable_action() try: contents = open(filename).read() @@ -142,30 +144,25 @@ class SourceWindow: def __init__(self): self.frame = None - # FIXME: set the size - # stuff in margins - self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) - self.window.set_border_width(0) - self.window.set_title('GDB Source') - self.window.set_size_request(600, 400) + self.do_step = Invoker("step") + self.do_next = Invoker("next") + self.do_continue = Invoker("continue") - vbox = gtk.VBox(0, False) - swin = gtk.ScrolledWindow() - self.view = gtksourceview.View() - self.view.set_editable(False) - self.view.set_cursor_visible(False) - self.view.set_highlight_current_line(True) - self.window.add(vbox) - vbox.pack_start(swin, True, True, 0) - swin.add(self.view) + builder = Gtk.Builder() + builder.add_from_file(os.path.join(gui.self_dir, 'sourcewindow.xml')) - vbox.show_all() + builder.connect_signals(self) + self.window = builder.get_object("sourcewindow") + self.view = builder.get_object("view") - self.window.connect("delete-event", self.deleted) lru_handler.add(self) self.window.show() + def do_stop(self, *args): + # FIXME. + pass + def deleted(self, widget, event): lru_handler.remove(self) @@ -180,5 +177,5 @@ class SourceWindow: old_buffer = self.view.get_buffer() self.view.set_buffer(buff) buffer_manager.release_buffer(old_buffer) - gtk.idle_add(self._do_scroll, buff, srcline - 1) + GObject.idle_add(self._do_scroll, buff, srcline - 1) # self.view.scroll_to_iter(buff.get_iter_at_line(srcline), 0.0) diff --git a/gui/sourcewindow.xml b/gui/sourcewindow.xml new file mode 100644 index 0000000..635e8ed --- /dev/null +++ b/gui/sourcewindow.xml @@ -0,0 +1,135 @@ + + + + + + True + False + icons/run-to-cursor.xpm + + + True + False + icons/step-over.xpm + + + True + False + icons/step-into.xpm + + + False + Source + 600 + 400 + + + + True + False + vertical + + + True + False + + + True + False + Continue execution + Continue + True + image1 + + + + + False + True + + + + + True + False + Execute one line, stepping over function calls + Next + True + image2 + + + + False + True + + + + + True + False + Execute one line, stepping into function calls + Step + True + image3 + + + + + False + True + + + + + True + False + Interrupt the program + Stop + True + gtk-stop + + + + + False + True + + + + + False + True + 0 + + + + + True + True + in + + + True + True + True + False + 2 + 2 + False + 4 + True + True + False + + + + + True + True + 1 + + + + + + diff --git a/gui/startup.py b/gui/startup.py index 47b86c9..0f384d6 100644 --- a/gui/startup.py +++ b/gui/startup.py @@ -20,8 +20,8 @@ import Queue import fix_signals fix_signals.save() -import gtk -import glib +from gi.repository import Gtk, Gdk, GObject, GtkSource + import os (read_pipe, write_pipe) = os.pipe() @@ -43,15 +43,17 @@ class _GtkThread(threading.Thread): def run(self): global read_pipe - glib.io_add_watch(read_pipe, glib.IO_IN, self.handle_queue) - gtk.main() + GObject.io_add_watch(read_pipe, GObject.IO_IN, self.handle_queue) + GObject.type_register(GtkSource.View) + Gtk.main() _t = None def start_gtk(): global _t if _t is None: - gtk.gdk.threads_init() + GObject.threads_init() + Gdk.threads_init() _t = _GtkThread() _t.setDaemon(True) _t.start()