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
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.

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.
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)

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
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()