source: trunk/debathena/debathena/console/debathena-console @ 23983

Revision 23983, 7.5 KB checked in by geofft, 15 years ago (diff)
In console: * Fix a line that used a variable before defining it. * Remove unwanted code left around from debugging.
  • Property svn:executable set to *
Line 
1#!/usr/bin/env python
2"""Debathena Console viewer
3Written by quentin@mit.edu
4
5Based on pygtk textview example code
6"""
7
8import os
9import sys
10import time
11
12import gobject
13import gtk
14import gconf
15import dbus, dbus.service
16import _dbus_bindings as dbus_bindings
17import dbus.mainloop.glib
18import wnck
19
20NAME = 'Console'
21
22# Supported gconf options:
23# /apps/debathena-console/blink
24# /apps/debathena-console/auto_hide
25# /apps/debathena-console/start_visible
26
27DBUS_IFACE="edu.mit.debathena.console"
28DBUS_BUS="edu.mit.debathena.console"
29DBUS_OBJECT="/edu/mit/debathena/console"
30
31class ConsoleDBus(dbus.service.Object):
32    def __init__(self, show_me, hide_me):
33        self.show_me = show_me
34        self.hide_me = hide_me
35        session_bus = dbus.SessionBus()
36        bus_name = dbus.service.BusName(DBUS_BUS, bus=session_bus)
37        object_path = DBUS_OBJECT
38        dbus.service.Object.__init__(self, bus_name, object_path)
39
40    @dbus.service.method(DBUS_IFACE,
41                         in_signature="b")
42    def set_visibility(self, visible):
43        if visible:
44            self.show_me(True)
45        else:
46            self.hide_me()
47
48class ConsoleViewer(gtk.Window):
49    def __init__(self, fds=[]):
50        # Create the toplevel window
51        gtk.Window.__init__(self)
52
53        self.connect('focus-in-event', self.on_focus)
54
55        self.set_focus_on_map(False)
56
57        client = gconf.client_get_default()
58        client.add_dir('/apps/debathena-console',
59                gconf.CLIENT_PRELOAD_ONELEVEL)
60        client.notify_add('/apps/debathena-console/blink',
61                self.new_blink)
62        client.notify_add('/apps/debathena-console/auto_hide',
63                self.new_auto_hide)
64        self.auto_hide_id = False
65        self.new_blink(client)
66        self.new_auto_hide(client)
67
68        self.systray = gtk.StatusIcon()
69        self.systray.set_from_stock("gtk-info")
70        self.systray.connect("activate", self.on_tray_activate, "activate")
71#        self.systray.connect("popup-menu", self.on_tray_popupmenu, self.popupmenu)
72        self.systray.set_tooltip(NAME)
73
74
75        self.set_title(NAME)
76        self.set_default_size(640, 320)
77        self.set_border_width(0)
78
79        vbox = gtk.VBox(False, 0)
80        self.add(vbox)
81
82        self.view = gtk.TextView();
83        buffer = self.view.get_buffer()
84
85        self.view.set_editable(False)
86        self.view.set_cursor_visible(False)
87        # See http://www.pygtk.org/docs/pygtk/gtk-constants.html#gtk-wrap-mode-constants
88        self.view.set_wrap_mode(gtk.WRAP_CHAR)
89
90        sw = gtk.ScrolledWindow()
91        sw.set_shadow_type(gtk.SHADOW_ETCHED_IN)
92        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
93
94        vbox.pack_start(sw)
95
96        sw.add(self.view)
97
98        bbox = gtk.HButtonBox()
99        bbox.set_border_width(5)
100        bbox.set_layout(gtk.BUTTONBOX_END)
101        bbox.set_spacing(40)
102
103        vbox.pack_start(bbox, expand=False)
104
105        def hide_window(*args):
106            gobject.idle_add(self.hide_me)
107            return True
108
109        button = gtk.Button("Hide")
110        button.connect("clicked", hide_window)
111        bbox.add(button)
112        self.connect('delete-event', hide_window)
113
114        self.create_tags(buffer)
115        self.insert_text(buffer)
116
117        # NB: we do show_all on the vbox so the widgets are ready
118        # when we present_with_time() inside show_me()
119        vbox.show_all()
120
121        if (client.get_bool("/apps/debathena-console/start_visible")):
122            self.show_me()
123
124        self.start_listening(buffer, self.view, fds)
125
126        self.dbus_service = ConsoleDBus(self.show_me, self.hide_me)
127        dbus.SessionBus().request_name(DBUS_BUS, dbus_bindings.NAME_FLAG_DO_NOT_QUEUE)
128
129    def new_blink(self, client, *a):
130        self.blink = client.get_bool("/apps/debathena-console/blink")
131
132    def new_auto_hide(self, client, *a):
133        self.auto_hide = client.get_int("/apps/debathena-console/auto_hide")
134        if self.auto_hide == 0 and self.auto_hide_id:
135            gobject.source_remove(self.auto_hide_id)
136            self.auto_hide_id = False
137
138    def on_tray_activate(self, widget, data=None):
139        if self.is_active():
140            self.hide_me()
141        else:
142            self.show_me(True)
143
144    def show_me(self, focus=False):
145        screen = wnck.screen_get_default()
146
147        active = screen.get_active_window()
148        if focus:
149            self.show_all()
150            self.window.focus()
151        elif not self.has_toplevel_focus():
152            # we need to be shown, but we're in the back
153            self.present_with_time(int(time.time()))
154            # restore the active window
155            while gtk.events_pending():
156                gtk.main_iteration()
157            if active:
158                active.activate(int(time.time()))
159
160        if self.auto_hide > 0:
161            if self.auto_hide_id:
162                gobject.source_remove(self.auto_hide_id)
163            self.auto_hide_id = gobject.timeout_add(self.auto_hide * 1000, self.hide_me)
164
165    def hide_me(self):
166        self.window.lower()
167        self.hide()
168        if self.auto_hide_id:
169            gobject.source_remove(self.auto_hide_id)
170            self.auto_hide_id = False
171        return False
172
173    def on_focus(self, widget, event):
174        self.systray.set_blinking(False)
175        return False
176
177    def create_tags(self, text_buffer):
178        '''
179        Create the tags we use for text (stdout and stderr)
180        '''
181
182        import pango
183
184        # See http://www.pygtk.org/docs/pygtk/class-gtktexttag.html
185        default_args = {'family': 'monospace',
186                        'size_points': 12}
187
188        text_buffer.create_tag("stdout", **default_args)
189        text_buffer.create_tag("stderr", foreground="red", **default_args)
190        text_buffer.create_tag("xconsole", weight=pango.WEIGHT_BOLD, **default_args)
191
192    def insert_text(self, text_buffer):
193        '''
194        Insert some sample text demonstrating the tags
195        '''
196        # get start of buffer; each insertion will revalidate the
197        # iterator to point to just after the inserted text.
198        iter = text_buffer.get_end_iter()
199
200    def start_listening(self, text_buffer, text_view, fds):
201        '''
202        Sets up a gobject event listener that adds text to the textview whenever
203        stdin has something to read
204        '''
205        def got_data(source, condition, tag):
206            data = source.read()
207            # act like tee, so the logs still end up in .xsession-errors
208            print data,
209            text_buffer.insert_with_tags_by_name(text_buffer.get_end_iter(),
210                                                 data, tag)
211
212            text_view.scroll_to_mark(text_buffer.create_mark(None, text_buffer.get_end_iter(), False), 0, False)
213
214            if self.blink and not self.has_toplevel_focus():
215                self.systray.set_blinking(True)
216            elif not self.has_toplevel_focus():
217                self.show_me()
218
219            if source.closed:
220                return False # we got an eof
221            else:
222                return True # causes callback to remain in existence
223        import fcntl, os
224        for i in range(len(fds)):
225            f = os.fdopen(fds[i][1])
226            fcntl.fcntl(fds[i][1], fcntl.F_SETFL, os.O_NONBLOCK)
227            gobject.io_add_watch(f, gobject.IO_IN, got_data, fds[i][0])
228
229def main():
230    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
231    if len(sys.argv) >= 2:
232        ConsoleViewer(fds=[(type, int(fd)) for x in sys.argv[1:]
233                            for type, fd in [x.split(':')]])
234    else:
235        ConsoleViewer(fds=[("stdout", 0)])
236    gtk.main()
237
238if __name__ == '__main__':
239    main()
Note: See TracBrowser for help on using the repository browser.