move to pygobject and glade

This ports the code to PyGObject, and also changes it to use Glade to
edit the user interface elements.
This commit is contained in:
Tom Tromey
2013-06-07 11:13:31 -06:00
parent 48cf179e8c
commit 5fceb3421e
17 changed files with 393 additions and 29 deletions

10
README
View File

@@ -15,14 +15,14 @@ GUIs in a few ways:
To get started, install the prerequisites. You'll need a To get started, install the prerequisites. You'll need a
Python-enabled gdb, PyGtk, and PyGktSourceView. (And maybe more -- if Python-enabled gdb, PyGObject, and PyGktSourceView. (And maybe more
you trip across something, let me know.) You'll need the Python -- if you trip across something, let me know.) You'll need the Python
development package to compile the small C module that is included development package to compile the small C module that is included
here. here.
On Fedora I think this suffices: 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 After you install this, type "make". Now, start gdb and source the
"SourceMe.py" file. This sets everything up. "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 is "gui source", which pops up a source window. The source window
will automatically track your progress when debugging. You can make will automatically track your progress when debugging. You can make
multiple source windows; they will be reused in an LRU fashion. 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.

View File

@@ -0,0 +1,18 @@
# Copyright (C) 2013 Tom Tromey <tom@tromey.com>
# 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 <http://www.gnu.org/licenses/>.
import os.path
self_dir = os.path.abspath(os.path.dirname(__file__))

1
gui/icons/README Normal file
View File

@@ -0,0 +1 @@
These icons were shamelessly taken from nemiver.

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 710 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 B

BIN
gui/icons/line-pointer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 B

View File

@@ -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",
" ",
" ",
" ",
" ........... ",
" .++++++++@.# ",
" .+++++@@@@.## ",
" .++@@$$@%%.... ",
" .@@@%$$%&&*==. ",
" .%%%%$$&*==--. ",
" .%&&*$$=---;;. ",
" .&*==$$;;;;>;. ",
" .=-$$$$$$>>,,. ",
" .;;;$$$$>,,,,. ",
" .;;>>$$,,,,,,. ",
" .>'''''''''',. ",
" .,'''''''''',. ",
" .,,,,,,,,,,,,. ",
" .,,,,,,,,,,,,. ",
" .............. ",
" ",
" ",
" "};

View File

@@ -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",
" ",
" ",
" ",
" ................ ",
" .++++++@#$$%%&*. ",
" .++++@#=-;%>&,'. ",
" .++))))))))))'!. ",
" .+@#=-;>&*,'!~{. ",
" .#=))))&,,!~{]^. ",
" .-;;;,,/////^//. ",
" .;(((((/)))__::. ",
" .>(((((/////:<[. ",
" .*(((((/))))<[[. ",
" .'(((((/:<<[[[[. ",
" .!(((((:_____[[. ",
" .{]/:::<[[[[[[[. ",
" .//))))))[[[[[[. ",
" .::<<[[[[[[[[[[. ",
" ................ ",
" ",
" ",
" "};

28
gui/icons/step-into.xpm Normal file
View File

@@ -0,0 +1,28 @@
/* XPM */
static char * step_in_xpm[] = {
"22 22 3 1",
" c None",
". c #FF0000",
"+ c #000000",
" ",
" ",
" ",
" ",
" ......... ",
" ......... ",
" .. ",
" ++ .. ++ ",
" ++......++ ",
" ++ .... ++ ",
" ++ .. ++ ",
" ++ ++ ",
" ++ ++ ",
" ++ ++ ",
" ++ ++ ",
" ++ ++ ",
" ++ ++ ",
" ++ ++ ",
" ",
" ",
" ",
" "};

28
gui/icons/step-out.xpm Normal file
View File

@@ -0,0 +1,28 @@
/* XPM */
static char * step_out_xpm[] = {
"22 22 3 1",
" c None",
". c #FF0000",
"+ c #000000",
" ",
" ",
" . ",
" .. ",
" ......... ",
" ......... ",
" .. .. ",
" ++ .. ++ . ",
" ++ .. ++ ",
" ++ .. ++ ",
" ++ .. ++ ",
" ++ ++ ",
" ++ ++ ",
" ++ ++ ",
" ++ ++ ",
" ++ ++ ",
" ++ ++ ",
" ++ ++ ",
" ",
" ",
" ",
" "};

28
gui/icons/step-over.xpm Normal file
View File

@@ -0,0 +1,28 @@
/* XPM */
static char * step_over_xpm[] = {
"22 22 3 1",
" c None",
". c #FF0000",
"+ c #000000",
" ",
" ",
" ",
" . ",
" .. ",
" ................ ",
" ................ ",
" .. ",
" ++ ++ . ",
" ++ ++ ",
" ++ ++ ",
" ++ ++ ",
" ++ ++ ",
" ++ ++ ",
" ++ ++ ",
" ++ ++ ",
" ++ ++ ",
" ++ ++ ",
" ++ ++ ",
" ",
" ",
" "};

BIN
gui/icons/throbber.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

31
gui/invoker.py Normal file
View File

@@ -0,0 +1,31 @@
# Copyright (C) 2013 Tom Tromey <tom@tromey.com>
# 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 <http://www.gnu.org/licenses/>.
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)

View File

@@ -16,9 +16,11 @@
# Source view. # Source view.
import gdb import gdb
from gui.invoker import Invoker
import gui.startup import gui.startup
import gtksourceview2 as gtksourceview import os.path
import gtk
from gi.repository import Gtk, GtkSource, GObject
class BufferManager: class BufferManager:
def __init__(self): def __init__(self):
@@ -32,7 +34,7 @@ class BufferManager:
if filename in self.buffers: if filename in self.buffers:
return self.buffers[filename] return self.buffers[filename]
buff = gtksourceview.Buffer() buff = GtkSource.Buffer()
buff.begin_not_undoable_action() buff.begin_not_undoable_action()
try: try:
contents = open(filename).read() contents = open(filename).read()
@@ -142,30 +144,25 @@ class SourceWindow:
def __init__(self): def __init__(self):
self.frame = None self.frame = None
# FIXME: set the size self.do_step = Invoker("step")
# stuff in margins self.do_next = Invoker("next")
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) self.do_continue = Invoker("continue")
self.window.set_border_width(0)
self.window.set_title('GDB Source')
self.window.set_size_request(600, 400)
vbox = gtk.VBox(0, False) builder = Gtk.Builder()
swin = gtk.ScrolledWindow() builder.add_from_file(os.path.join(gui.self_dir, 'sourcewindow.xml'))
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)
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) lru_handler.add(self)
self.window.show() self.window.show()
def do_stop(self, *args):
# FIXME.
pass
def deleted(self, widget, event): def deleted(self, widget, event):
lru_handler.remove(self) lru_handler.remove(self)
@@ -180,5 +177,5 @@ class SourceWindow:
old_buffer = self.view.get_buffer() old_buffer = self.view.get_buffer()
self.view.set_buffer(buff) self.view.set_buffer(buff)
buffer_manager.release_buffer(old_buffer) 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) # self.view.scroll_to_iter(buff.get_iter_at_line(srcline), 0.0)

135
gui/sourcewindow.xml Normal file
View File

@@ -0,0 +1,135 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<!-- interface-requires gtksourceview 3.0 -->
<object class="GtkImage" id="image1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="pixbuf">icons/run-to-cursor.xpm</property>
</object>
<object class="GtkImage" id="image2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="pixbuf">icons/step-over.xpm</property>
</object>
<object class="GtkImage" id="image3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="pixbuf">icons/step-into.xpm</property>
</object>
<object class="GtkWindow" id="sourcewindow">
<property name="can_focus">False</property>
<property name="title" translatable="yes">Source</property>
<property name="default_width">600</property>
<property name="default_height">400</property>
<signal name="delete-event" handler="deleted" swapped="no"/>
<child>
<object class="GtkBox" id="box1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkToolbar" id="toolbar1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkToolButton" id="continue">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Continue execution</property>
<property name="label" translatable="yes">Continue</property>
<property name="use_underline">True</property>
<property name="icon_widget">image1</property>
<accelerator key="c" signal="clicked"/>
<signal name="clicked" handler="do_continue" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="next">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Execute one line, stepping over function calls</property>
<property name="label" translatable="yes">Next</property>
<property name="use_underline">True</property>
<property name="icon_widget">image2</property>
<accelerator key="n" signal="clicked"/>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="step">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Execute one line, stepping into function calls</property>
<property name="label" translatable="yes">Step</property>
<property name="use_underline">True</property>
<property name="icon_widget">image3</property>
<accelerator key="s" signal="clicked"/>
<signal name="clicked" handler="do_step" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
<child>
<object class="GtkToolButton" id="stop">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="tooltip_text" translatable="yes">Interrupt the program</property>
<property name="label" translatable="yes">Stop</property>
<property name="use_underline">True</property>
<property name="stock_id">gtk-stop</property>
<accelerator key="c" signal="clicked" modifiers="GDK_CONTROL_MASK"/>
<signal name="clicked" handler="do_stop" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="homogeneous">True</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow2">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkSourceView" id="view">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="has_tooltip">True</property>
<property name="editable">False</property>
<property name="left_margin">2</property>
<property name="right_margin">2</property>
<property name="cursor_visible">False</property>
<property name="tab_width">4</property>
<property name="auto_indent">True</property>
<property name="highlight_current_line">True</property>
<property name="indent_on_tab">False</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

View File

@@ -20,8 +20,8 @@ import Queue
import fix_signals import fix_signals
fix_signals.save() fix_signals.save()
import gtk from gi.repository import Gtk, Gdk, GObject, GtkSource
import glib
import os import os
(read_pipe, write_pipe) = os.pipe() (read_pipe, write_pipe) = os.pipe()
@@ -43,15 +43,17 @@ class _GtkThread(threading.Thread):
def run(self): def run(self):
global read_pipe global read_pipe
glib.io_add_watch(read_pipe, glib.IO_IN, self.handle_queue) GObject.io_add_watch(read_pipe, GObject.IO_IN, self.handle_queue)
gtk.main() GObject.type_register(GtkSource.View)
Gtk.main()
_t = None _t = None
def start_gtk(): def start_gtk():
global _t global _t
if _t is None: if _t is None:
gtk.gdk.threads_init() GObject.threads_init()
Gdk.threads_init()
_t = _GtkThread() _t = _GtkThread()
_t.setDaemon(True) _t.setDaemon(True)
_t.start() _t.start()