Fix GtkNotebook issues.
[laditools.git] / bin / ladilog
blob4cc8d61db5108edf23a4dc2bbd9041d0069be923
1 #!/usr/bin/python
3 # LADITools - Linux Audio Desktop Integration Tools
4 # ladilog - A log viewer for your Linux Audio Desktop
5 # Copyright (C) 2011-2012 Alessio Treglia <quadrispro@ubuntu.com>
6 # Copyright (C) 2007-2010, Marc-Olivier Barre <marco@marcochapeau.org>
7 # Copyright (C) 2007-2009, Nedko Arnaudov <nedko@arnaudov.name>
9 # This program is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <http://www.gnu.org/licenses/>.
22 import os
23 import sys
24 import signal
25 from subprocess import Popen, PIPE
26 import pty
27 from signal import SIGTERM
28 import termios
29 import tty
30 import gettext
31 import argparse
33 sig_handler = signal.getsignal(signal.SIGTERM)
34 signal.signal(signal.SIGINT, sig_handler)
36 try:
37 import imp
38 imp.find_module('laditools')
39 except ImportError:
40 # Running from the build tree?
41 sys.path.insert(0, os.path.join(sys.path[0], os.pardir))
43 from laditools import _gettext_domain
44 gettext.install(_gettext_domain)
46 from laditools import get_version_string
47 from laditools import LadiConfiguration
49 from gi.repository import Gtk
50 from gi.repository import GObject
51 from gi.repository import Vte
53 from laditools.gtk import find_data_file
55 timeout_add = GObject.timeout_add
57 # Default configuration
58 max_lines_default = 100
60 # Output the last <lines> lines
61 def read_last(lfile, lines):
62 chunk_size = lines * 60
63 lfile.seek(0, 2)
64 endpos = lfile.tell()
65 pos = endpos - chunk_size
66 if pos < 0:
67 pos = 0
68 backlog = ''
69 backlog_size = 0
70 lines += 1
71 while pos >= 0 and backlog_size <= lines:
72 lfile.seek(pos, 0)
73 s = lfile.read(chunk_size)
74 pos = pos - chunk_size
75 backlog_size += s.count("\n")
76 backlog = s + backlog
77 backlog = backlog.strip().split("\n")
78 if len(backlog) > lines:
79 backlog = backlog[-lines:]
80 lfile.seek(endpos, 0)
81 return backlog
83 class ladilog(object):
84 def __init__ (self):
85 self.log_files = [
87 'name': 'JACK',
88 'config_name': 'jackdbus_log',
89 'config_default': os.sep.join([os.environ['HOME'], ".log", "jack", "jackdbus.log"])
92 'name': 'LADISH',
93 'config_name': 'ladish_log',
94 'config_default': os.sep.join([os.environ['HOME'], ".log", "ladish", "ladish.log"])
97 'name': 'A2J',
98 'config_name': 'a2j_log',
99 'config_default': os.sep.join([os.environ['HOME'], ".log", "a2j", "a2j.log"])
102 # Handle the configuration
103 self.global_config = LadiConfiguration ()
104 self.param_dict = self.global_config.get_config_section ('ladilog')
106 for log in self.log_files:
107 if self.param_dict != None:
108 if log['config_name'] not in self.param_dict:
109 self.param_dict[log['config_name']] = log['config_default']
110 else:
111 self.param_dict = {}
112 self.param_dict[log['config_name']] = log['config_default']
114 if 'max_lines' not in self.param_dict:
115 self.param_dict['max_lines'] = max_lines_default
117 for log in self.log_files[:]:
118 log['logfile_path'] = self.param_dict[log['config_name']]
119 # skip logfiles that dont exist
120 if not os.access(log['logfile_path'], os.R_OK):
121 self.log_files.remove(log)
122 sys.stderr.write( _("Skipping '%s' because it does not exist\n") % log['logfile_path'])
123 else:
124 sys.stderr.write( _("Watching %s\n") % log['logfile_path'])
125 sys.stderr.flush()
127 max_lines_text = self.param_dict['max_lines']
128 self.max_lines = int (max_lines_text)
129 # Load the glade file
130 builder = Gtk.Builder()
131 builder.add_from_file(find_data_file("ladilog_ui.ui"))
132 sys.stderr.write( _("Loading interface from %s\n") % find_data_file("ladilog_ui.ui"))
133 sys.stderr.flush()
134 # Get the ui ready for action
135 self.event_dict = {"on_ladilog_ui_destroy" : self.on_quit,
136 "on_ladilog_ui_delete" : self.on_delete,
137 "on_close_button_clicked" : self.on_quit,
138 "on_clear_button_clicked" : self.on_clear_text,
139 "on_purge_button_clicked" : self.on_purge}
140 builder.connect_signals(self.event_dict)
142 self.ui = ui = builder.get_object("ladilog_ui")
143 self.logview_notebook = builder.get_object ("ladilog_notebook")
144 # Create our terminal and display it
145 for log in self.log_files:
146 log['scrolled_window'] = sw = Gtk.ScrolledWindow()
147 log['term'] = term = Vte.Terminal.new ()
148 sw.set_policy(hscrollbar_policy=Gtk.PolicyType.AUTOMATIC,
149 vscrollbar_policy=Gtk.PolicyType.ALWAYS)
150 sw.add(term)
151 sw.show()
152 term.set_scroll_on_output(True)
153 log["tab_label"] = Gtk.Label(label=log["name"])
155 self.logview_notebook.append_page(log["scrolled_window"],
156 log["tab_label"])
158 # Make it do something...
159 for log in self.log_files:
160 try:
161 log['log_file'] = open(log['logfile_path'], "rb")
162 sys.stderr.write (_("Opening %s...\n") % log['logfile_path'])
163 lines = read_last(log['log_file'], self.max_lines)
164 for line in lines:
165 line = line.strip('\r\n') + '\r\n'
166 log["term"].feed(line, -1)
167 except ValueError:
168 sys.stderr.write( _("You called Popen with invalid arguments... dumbass\n") )
169 except:
170 sys.stderr.write( _("Unexpected error: %s\n") % (sys.exc_info ()[0]))
171 finally:
172 sys.stderr.flush()
174 ui.show_all()
175 self.auto_updater = timeout_add(250, self.update)
177 def update(self):
178 # Append latest output to the buffer
179 for log in self.log_files:
180 line = log['log_file'].readline()
181 while line:
182 log["term"].feed(line + '\r', -1)
183 line = log['log_file'].readline()
184 log['log_file'].seek(log['log_file'].tell())
185 return True
187 def on_delete(self, widget=None, data=None):
188 return False
190 def on_quit (self, data=None):
191 Gtk.main_quit ()
193 def on_clear_text (self, data=None):
194 current_view = self.logview_notebook.get_current_page ()
195 self.log_files[current_view]["term"].feed ("\033[2J\033[;f", -1)
197 def on_purge (self, data=None):
198 current_view = self.logview_notebook.get_current_page ()
199 # Opens the file in write anew mode thus clearing the file and close it right away
200 open (self.log_files[current_view]['logfile_path'], "w+")
201 self.log_files[current_view]["term"].feed ("\033[2J\033[;f", -1)
203 def run (self):
204 Gtk.main ()
205 self.global_config.set_config_section ("ladilog", self.param_dict)
206 self.global_config.save ()
207 return 0
209 #try:
210 if __name__ == '__main__':
211 parser = argparse.ArgumentParser(description=_('JACK, ladish and a2jmidid log viewer'),
212 epilog=_('This program is part of the LADITools suite.'))
213 parser.add_argument('--version', action='version', version="%(prog)s " + get_version_string())
215 parser.parse_args()
216 ladilog().run()
217 sys.exit(0)
218 #except Exception, e:
219 # error = Gtk.MessageDialog(None,
220 # Gtk.DialogFlags.MODAL,
221 # Gtk.MessageType.ERROR,
222 # Gtk.ButtonsType.OK,
223 # _("Unexpected error\n\n") + repr(e))
224 # error.run()
225 # sys.exit(1)