def __init__(self): self.DEBUG = DEBUG import gettext #this is for the glade files self.glade_gettext = gettext.textdomain("specto") self.logger = Logger(self) self.check_instance() #see if specto is already running self.util = util self.PATH = self.util.get_path() self.specto_gconf = specto_gconf self.check_default_settings( ) #if this is the first run of specto, set the default values for gconf. Whenever you add some gconf preference for specto, this function will also need to be updated. self.GTK = GTK if GTK: self.tray = Tray(self) self.icon_theme = gtk.icon_theme_get_default() self.watch_db = {} self.watch_io = Watch_io() watch_value_db = self.watch_io.read_options() self.preferences_initialized = False self.notifier_initialized = False #listen for gconf keys self.specto_gconf.notify_entry("debug_mode", self.key_changed, "debug") self.connection_manager = conmgr.get_net_listener() if GTK: if self.specto_gconf.get_entry("always_show_icon") == False: #if the user has not requested the tray icon to be shown at all times, it's impossible that the notifier is hidden on startup, so we must show it. self.notifier_keep_hidden = False self.toggle_notifier() elif self.specto_gconf.get_entry("show_notifier") == True: self.notifier_keep_hidden = False self.toggle_notifier() elif self.specto_gconf.get_entry("show_notifier") == False: self.notifier_keep_hidden = True self.toggle_notifier() self.notifier_keep_hidden = False else: #just in case the entry was never created in gconf self.notifier_keep_hidden = False self.toggle_notifier() self.create_all_watches(watch_value_db) if GTK: gtk.main() else: self.go = gobject.MainLoop() self.go.run()
def __init__(self): self.DEBUG = DEBUG import gettext #this is for the glade files self.glade_gettext = gettext.textdomain("specto") self.logger = Logger(self) self.check_instance() #see if specto is already running self.util = util self.PATH = self.util.get_path() self.specto_gconf = specto_gconf self.check_default_settings()#if this is the first run of specto, set the default values for gconf. Whenever you add some gconf preference for specto, this function will also need to be updated. self.GTK = GTK if GTK: self.tray = Tray(self) self.icon_theme = gtk.icon_theme_get_default() self.watch_db = {} self.watch_io = Watch_io() watch_value_db = self.watch_io.read_options() self.preferences_initialized = False self.notifier_initialized = False #listen for gconf keys self.specto_gconf.notify_entry("debug_mode", self.key_changed, "debug") self.connection_manager = conmgr.get_net_listener() if GTK: if self.specto_gconf.get_entry("always_show_icon") == False: #if the user has not requested the tray icon to be shown at all times, it's impossible that the notifier is hidden on startup, so we must show it. self.notifier_keep_hidden = False self.toggle_notifier() elif self.specto_gconf.get_entry("show_notifier")==True: self.notifier_keep_hidden = False self.toggle_notifier() elif self.specto_gconf.get_entry("show_notifier")==False: self.notifier_keep_hidden = True self.toggle_notifier() self.notifier_keep_hidden = False else:#just in case the entry was never created in gconf self.notifier_keep_hidden = False self.toggle_notifier() self.create_all_watches(watch_value_db) if GTK: gtk.main() else: self.go = gobject.MainLoop() self.go.run()
class Specto: """ The main Specto class. """ add_w = "" edit_w = "" error_l = "" about = "" export = "" def __init__(self): self.DEBUG = DEBUG import gettext #this is for the glade files self.glade_gettext = gettext.textdomain("specto") self.logger = Logger(self) self.check_instance() #see if specto is already running self.util = util self.PATH = self.util.get_path() self.specto_gconf = specto_gconf self.check_default_settings( ) #if this is the first run of specto, set the default values for gconf. Whenever you add some gconf preference for specto, this function will also need to be updated. self.GTK = GTK if GTK: self.tray = Tray(self) self.icon_theme = gtk.icon_theme_get_default() self.watch_db = {} self.watch_io = Watch_io() watch_value_db = self.watch_io.read_options() self.preferences_initialized = False self.notifier_initialized = False #listen for gconf keys self.specto_gconf.notify_entry("debug_mode", self.key_changed, "debug") self.connection_manager = conmgr.get_net_listener() if GTK: if self.specto_gconf.get_entry("always_show_icon") == False: #if the user has not requested the tray icon to be shown at all times, it's impossible that the notifier is hidden on startup, so we must show it. self.notifier_keep_hidden = False self.toggle_notifier() elif self.specto_gconf.get_entry("show_notifier") == True: self.notifier_keep_hidden = False self.toggle_notifier() elif self.specto_gconf.get_entry("show_notifier") == False: self.notifier_keep_hidden = True self.toggle_notifier() self.notifier_keep_hidden = False else: #just in case the entry was never created in gconf self.notifier_keep_hidden = False self.toggle_notifier() self.create_all_watches(watch_value_db) if GTK: gtk.main() else: self.go = gobject.MainLoop() self.go.run() def key_changed(self, *args): """ Listen for gconf keys. """ label = args[3] if label == "debug": self.DEBUG = self.specto_gconf.get_entry("debug_mode") def check_default_settings(self): """ This is used to set the default settings properly the first time Specto is run, without using gconf schemas """ self.default_settings = ( ["always_show_icon", False], #having it True would be against the HIG! ["debug_mode", False], ["follow_website_redirects", True], ["pop_toast_duration", 5], ["pop_toast", True], ["show_deactivated_watches", True], ["show_in_windowlist", True], ["show_notifier", True], ["show_toolbar", True], ["sort_function", "name"], ["sort_order", "asc"], ["update_sound", "/usr/share/sounds/ekiga/voicemail.wav"], ["use_update_sound", False], ["window_notifier_height", 500], ["window_notifier_width", 500]) for default_setting in self.default_settings: if self.specto_gconf.get_entry( default_setting[0] ) == None: #the key has no user-defined value or does not exist self.specto_gconf.set_entry(default_setting[0], default_setting[1]) def check_instance(self): """ Check if specto is already running. """ pidfile = os.environ['HOME'] + "/.specto/" + "specto.pid" if not os.path.exists(pidfile): f = open(pidfile, "w") f.close() os.chmod(pidfile, 0600) #see if specto is already running f = open(pidfile, "r") pid = f.readline() f.close() if pid: p = os.system("ps --no-heading --pid " + pid) p_name = os.popen("ps -f --pid " + pid).read() if p == 0 and "specto" in p_name: self.logger.log(_("Specto is already running!"), "critical", self.__class__) sys.exit(0) #write the pid file f = open(pidfile, "w") f.write(str(os.getpid())) f.close() def recreate_tray(self, *args): """ Recreate a tray icon if the notification area unexpectedly quits. """ try: self.tray.destroy() except: pass self.tray = "" self.tray = Tray(self) self.count_updated_watches() def create_all_watches(self, value_db): """ Create the watches at startup. """ for i in value_db: self.create_watch(value_db[i]) if GTK: while gtk.events_pending(): gtk.main_iteration_do(False) if self.specto_gconf.get_entry("show_deactivated_watches") == True: self.notifier.wTree.get_widget("display_all_watches").set_active( True) self.notifier.toggle_show_deactivated_watches( startup=True ) #True makes startup=True, only used on the first startup to avoid duplicate watches. #start the active watches if self.notifier_initialized: self.notifier.refresh() def create_watch(self, values): """ Add a watch to the watches repository. """ id = len(self.watch_db) if values['type'] == 0: #add a website from spectlib.watch_web_static import Web_watch self.watch_db[id] = Web_watch( self, values['name'], values['refresh'], values['uri'], id, values['error_margin']) #TODO: Authentication elif values['type'] == 1: #add an email if int(values['prot']) == 0: #check if pop3, imap or gmail is used import spectlib.watch_mail_pop3 self.watch_db[id] = spectlib.watch_mail_pop3.Mail_watch( values['refresh'], values['host'], values['username'], values['password'], values['ssl'], self, id, values['name']) elif int(values['prot']) == 1: import spectlib.watch_mail_imap self.watch_db[id] = spectlib.watch_mail_imap.Mail_watch( values['refresh'], values['host'], values['username'], values['password'], values['ssl'], self, id, values['name']) else: import spectlib.watch_mail_gmail self.watch_db[id] = spectlib.watch_mail_gmail.Mail_watch( values['refresh'], values['username'], values['password'], self, id, values['name']) elif values['type'] == 2: #add a file from spectlib.watch_file import File_watch self.watch_db[id] = File_watch(values['refresh'], values['file'], values['mode'], self, id, values['name']) elif values['type'] == 3: #add a process watch from spectlib.watch_process import Process_watch self.watch_db[id] = Process_watch(values['refresh'], values['process'], self, id, values['name']) elif values['type'] == 4: #add a port watch from spectlib.watch_port import Port_watch self.watch_db[id] = Port_watch(values['refresh'], values['port'], self, id, values['name']) elif values['type'] == 5: #add a google reader account from spectlib.watch_web_greader import Google_reader self.watch_db[id] = Google_reader(values['refresh'], values['username'], values['password'], self, id, values['name']) try: self.watch_db[id].updated = values['updated'] except: self.watch_db[id].updated = False try: self.watch_db[id].active = values['active'] except: self.watch_db[id].active = True try: self.watch_db[id].last_updated = values['last_updated'] except: self.watch_db[id].last_updated = _("No updates yet.") if GTK: if not self.notifier_initialized: self.notifier = Notifier(self) #self.notifier.restore_size_and_position()#fixme: is this necessary? this makes specto output stuff for nothing. self.notifier.add_notifier_entry(values['name'], values['type'], id) try: if values['updated']: self.toggle_updated(id) except: pass try: if values['active'] == False: self.notifier.deactivate(id) except: pass return id def clear_watch(self, id): """ Mark a watch as not updated. """ new_values = {} self.watch_db[id].updated = False new_values['name'] = self.watch_db[id].name new_values['updated'] = False self.watch_io.write_options(new_values) self.count_updated_watches() def mark_watch_busy(self, progress, id): """ Display a refresh icon when updating watches. """ self.notifier.toggle_updating(progress, id) def set_status(self, id, status): """ Set the status from a watch (active/not active). """ new_values = {} new_values['name'] = self.watch_db[id].name new_values['active'] = status if status == False: new_values['updated'] = False self.watch_db[id].updated = False self.notifier.clear_watch('', id) self.watch_db[id].active = status self.watch_io.write_options(new_values) def replace_name(self, orig, new): """ Replace the name from a watch in watches.list. """ self.watch_io.replace_name(orig, new) def start_watch(self, id): """ Start a watch. """ self.notifier.toggle_updating(True, id) self.watch_db[id].start_watch() self.logger.log( _("watch \"%s\" started") % self.watch_db[id].name, "info", self.__class__) def stop_watch(self, id): """ Stop a watch. """ self.watch_db[id].stop_watch() self.logger.log( _("watch \"%s\" stopped") % self.watch_db[id].name, "info", self.__class__) def add_watch(self, values): """ Add a new watch. """ new_values = {} new_values['name'] = values['name'] new_values['type'] = values['type'] new_values['refresh'] = self.set_interval(values['refresh_value'], values['refresh_unit']) if int(values['type']) == 0: #web new_values['uri'] = values['url'] new_values['error_margin'] = values['error_margin'] elif int(values['type']) == 1: #mail if int(values['prot']) == 0 or int(values['prot']) == 1: new_values['host'] = values['host'] new_values['ssl'] = values['ssl'] new_values['username'] = values['username'] new_values['password'] = values['password'] new_values['prot'] = values['prot'] elif int(values['type']) == 2: #file new_values['file'] = values['file'] new_values['mode'] = values['mode'] elif int(values['type']) == 3: #process new_values['process'] = values['process'] elif int(values['type']) == 4: #port new_values['port'] = values['port'] elif int(values['type']) == 5: #google reader new_values['username'] = values['username'] new_values['password'] = values['password'] id = self.create_watch(new_values) self.start_watch(id) self.watch_io.write_options(new_values) def edit_watch(self, values): """ Edit a watch. """ new_values = {} new_values['name'] = values['name'] new_values['type'] = values['type'] new_values['refresh'] = self.set_interval(values['refresh_value'], values['refresh_unit']) if int(values['type']) == 0: #web new_values['uri'] = values['url'] new_values['error_margin'] = values['error_margin'] elif int(values['type']) == 1: #mail if int( values['prot'] ) != 2: #gmail doesn't need a host and SSL it seems, so this is updated only of it's another kind of mail watch new_values['host'] = values['host'] new_values['ssl'] = values['ssl'] new_values['username'] = values['username'] new_values['password'] = values['password'] new_values['prot'] = values['prot'] elif int(values['type']) == 2: #file new_values['file'] = values['file'] elif int(values['type']) == 3: #process new_values['process'] = values['process'] elif int(values['type']) == 4: #port new_values['port'] = values['port'] elif int(values['type']) == 5: #google reader new_values['username'] = values['username'] new_values['password'] = values['password'] self.watch_io.write_options(new_values) self.notifier.show_watch_info() def remove_watch(self, name, id): """ Remove a watch. """ try: self.stop_watch(id) except: pass del self.watch_db[id] self.count_updated_watches() self.watch_io.remove_watch( name ) #do not clear the watch after removing it or it will mess up the watches.list self.notifier.model.remove(self.notifier.iter[id]) def find_watch(self, name): """ Returns the key of a watch or None if it doesn't exists. """ k = -1 for key in self.watch_db.iterkeys(): if self.watch_db[key].name == name: k = key break return k def check_unique_watch(self, name): """ Check if the watch name is unique. """ if self.watch_io.search_watch(name) and GTK: return False else: return True def count_updated_watches(self): """ Count the number of updated watches for the tooltip. """ tooltip_updated_watches = { 0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0 } #don't forget to update this if you are implementing a new type of watch for i in self.watch_db: if self.watch_db[i].updated == True: self.tray.set_icon_state_excited( ) #change the tray icon color to orange tooltip_updated_watches[self.watch_db[i].type] += 1 if tooltip_updated_watches.values() == [ 0, 0, 0, 0, 0, 0 ]: #there are no more watches to clear, reset the tray icon self.tray.set_icon_state_normal() self.notifier.wTree.get_widget("button_clear_all").set_sensitive( False) self.tray.show_tooltip(tooltip_updated_watches) def toggle_updated(self, id): """ When a watch is updated: change name in notifier window, change the tray icon state, play a sound, ... """ new_values = {} now = datetime.today() #TODO:XXX:GETTEXT new_values['last_updated'] = now.strftime("%A %d %b %Y %H:%M") self.watch_db[id].last_updated = now.strftime("%A %d %b %Y %H:%M") self.watch_db[id].updated = True if self.notifier_initialized: self.notifier.toggle_updated(id) new_values['name'] = self.watch_db[id].name new_values['updated'] = True self.watch_io.write_options( new_values) #write the watches state in watches.list self.count_updated_watches() #show the tooltip def toggle_all_cleared(self): """ Set the state from all the watches back to 'not updated'. """ for i in self.watch_db: new_values = {} self.watch_db[i].updated = False new_values['name'] = self.watch_db[i].name new_values['updated'] = False self.watch_io.write_options(new_values) self.count_updated_watches() def set_interval(self, refresh, refresh_unit): """ Set the interval between the update checks. refresh = number refresh_unit = days, hours, minutes,... in values of 0, 1, 2, 3. """ new_refresh = 0 if refresh_unit == 0: #seconds new_refresh = refresh * 1000 elif refresh_unit == 1: #minutes new_refresh = refresh * 60 * 1000 elif refresh_unit == 2: #hours new_refresh = (refresh * 60) * 60 * 1000 elif refresh_unit == 3: #days new_refresh = ((refresh * 60) * 60) * 24 * 1000 return new_refresh def get_interval(self, value): """ Get the interval between 2 updates. """ if ((value / 60) / 60) / 24 / 1000 > 0: refresh_value = ((value / 60) / 60) / 24 / 1000 type = 3 elif (value / 60) / 60 / 1000 > 0: refresh_value = (value / 60) / 60 / 1000 type = 2 elif value / 60 / 1000 > 0: refresh_value = value / 60 / 1000 type = 1 else: refresh_value = value / 1000 type = 0 return refresh_value, type def toggle_notifier(self, *args): """ Toggle the state of the notifier, hidden or shown. It will save the size, position, and the last state when you closed Specto. """ #Creating the notifier window, but keeping it hidden if not self.notifier_initialized and self.notifier_keep_hidden: self.notifier = Notifier(self) #self.notifier.restore_size_and_position()#this is NOT needed here because it already does that on instanciation on the line above -kiddo self.notifier.notifier.hide() #Creating the notifier window and displaying it elif not self.notifier_initialized and not self.notifier_keep_hidden: self.notifier = Notifier(self) #self.notifier.restore_size_and_position()#this is NOT needed here because it already does that on instanciation on the line above -kiddo self.notifier.notifier.show() elif self.notifier_initialized: if self.notifier.get_state() == True and self.notifier_keep_hidden: self.logger.log(_("notifier: reappear"), "debug", self.__class__) self.specto_gconf.set_entry("show_notifier", True) self.notifier.restore_size_and_position( ) #to make sure that the x and y positions don't jump around self.notifier.notifier.show() elif self.notifier.get_state( ) == True and not self.notifier_keep_hidden: self.logger.log(_("notifier: hide"), "debug", self.__class__) self.specto_gconf.set_entry("show_notifier", False) self.notifier.notifier.hide() else: self.logger.log(_("notifier: reappear"), "debug", self.__class__) self.specto_gconf.set_entry("show_notifier", True) self.notifier.restore_size_and_position( ) #to make sure that the x and y positions don't jump around self.notifier.notifier.show() self.notifier_initialized = True def show_preferences(self, *args): """ Show the preferences window. """ if not self.preferences_initialized or self.preferences.get_state( ) == True: self.logger.log(_("preferences: create"), "debug", self.__class__) self.pref = Preferences(self) else: self.logger.log(_("preferences: reappear"), "debug", self.__class__) self.pref.show() def show_error_log(self, *args): """ Show the error log. """ if self.error_l == "": self.error_l = Log_dialog(self) self.logger.log(_("error log: create"), "debug", self.__class__) elif self.error_l.log_dialog.flags() & gtk.MAPPED: self.logger.log(_("error log: already visible"), "debug", self.__class__) else: self.error_l = Log_dialog(self) self.logger.log(_("error log: recreate"), "debug", self.__class__) def show_add_watch(self, *args): """ Show the add watch window. """ if self.add_w == "": self.add_w = Add_watch(self) self.logger.log(_("add watch: create"), "debug", self.__class__) elif self.add_w.add_watch.flags() & gtk.MAPPED: self.logger.log(_("add watch: already visible"), "debug", self.__class__) else: self.add_w = Add_watch(self) self.logger.log(_("add watch: recreate"), "debug", self.__class__) def show_edit_watch(self, id, *args): """ Show the edit watch window. """ selected = "" if not id == -1: selected = self.watch_db[id] else: for i in self.watch_db: if self.watch_db[i].name == args[0]: selected = self.watch_db[i] if self.edit_w == "": self.edit_w = Edit_watch(self, selected) self.logger.log(_("edit watch: create"), "debug", self.__class__) elif self.edit_w.edit_watch.flags() & gtk.MAPPED: self.logger.log(_("edit watch: already visible"), "debug", self.__class__) else: self.edit_w = Edit_watch(self, selected) self.logger.log(_("edit watch: recreate"), "debug", self.__class__) def show_about(self, *args): """ Show the about window. """ if self.about == "": self.about = About(self) elif self.about.about.flags() & gtk.MAPPED: pass else: self.about = About(self) def show_help(self, *args): """ Show the help web page. """ self.util.show_webpage("http://code.google.com/p/specto/w/list") def import_export_watches(self, action): """ Show the import/export window. """ if self.export == "": self.export = Import_watch(self, action) elif self.export.import_watch.flags() & gtk.MAPPED: pass else: self.export = Import_watch(self, action) def quit(self, *args): """ Save the save and position from the notifier and quit Specto. """ if self.notifier.get_state() == True and not self.notifier_keep_hidden: self.notifier.save_size_and_position( ) #when quitting specto abruptly, remember the notifier window properties try: gtk.main_quit() except: #create a close dialog dialog = gtk.Dialog( _("Cannot quit yet"), None, gtk.DIALOG_MODAL | gtk.DIALOG_NO_SEPARATOR | gtk.DIALOG_DESTROY_WITH_PARENT, None) #HIG tricks dialog.set_has_separator(False) dialog.add_button(_("Murder!"), 3) dialog.add_button(gtk.STOCK_CANCEL, -1) dialog.label_hbox = gtk.HBox(spacing=6) icon = gtk.Image() icon.set_from_icon_name("dialog-warning", 64) dialog.label_hbox.pack_start(icon, True, True, 6) icon.show() label = gtk.Label( _('<b><big>Specto is currently busy and cannot quit yet.</big></b>\n\nThis may be because it is checking for watch updates.\nHowever, you can try forcing it to quit by clicking the murder button.' )) label.set_use_markup(True) dialog.label_hbox.pack_start( label, True, True, 6 ) #here, pack means "cram the label right at the start of the vbox before the buttons" label.show() dialog.vbox.pack_start(dialog.label_hbox, True, True, 12) dialog.label_hbox.show() icon = gtk.gdk.pixbuf_new_from_file(self.PATH + 'icons/specto_window_icon.svg') dialog.set_icon(icon) answer = dialog.run() if answer == 3: try: #go figure, it never works! self.notifier.stop_refresh = True sys.exit(0) except: #kill the specto process with killall os.system('killall specto') else: dialog.destroy()
class Specto: """ The main Specto class. """ add_w = "" edit_w = "" error_l = "" about = "" export = "" def __init__(self): self.DEBUG = DEBUG import gettext #this is for the glade files self.glade_gettext = gettext.textdomain("specto") self.logger = Logger(self) self.check_instance() #see if specto is already running self.util = util self.PATH = self.util.get_path() self.specto_gconf = specto_gconf self.check_default_settings()#if this is the first run of specto, set the default values for gconf. Whenever you add some gconf preference for specto, this function will also need to be updated. self.GTK = GTK if GTK: self.tray = Tray(self) self.icon_theme = gtk.icon_theme_get_default() self.watch_db = {} self.watch_io = Watch_io() watch_value_db = self.watch_io.read_options() self.preferences_initialized = False self.notifier_initialized = False #listen for gconf keys self.specto_gconf.notify_entry("debug_mode", self.key_changed, "debug") self.connection_manager = conmgr.get_net_listener() if GTK: if self.specto_gconf.get_entry("always_show_icon") == False: #if the user has not requested the tray icon to be shown at all times, it's impossible that the notifier is hidden on startup, so we must show it. self.notifier_keep_hidden = False self.toggle_notifier() elif self.specto_gconf.get_entry("show_notifier")==True: self.notifier_keep_hidden = False self.toggle_notifier() elif self.specto_gconf.get_entry("show_notifier")==False: self.notifier_keep_hidden = True self.toggle_notifier() self.notifier_keep_hidden = False else:#just in case the entry was never created in gconf self.notifier_keep_hidden = False self.toggle_notifier() self.create_all_watches(watch_value_db) if GTK: gtk.main() else: self.go = gobject.MainLoop() self.go.run() def key_changed(self, *args): """ Listen for gconf keys. """ label = args[3] if label == "debug": self.DEBUG = self.specto_gconf.get_entry("debug_mode") def check_default_settings(self): """ This is used to set the default settings properly the first time Specto is run, without using gconf schemas """ self.default_settings=( ["always_show_icon", False], #having it True would be against the HIG! ["debug_mode", False], ["follow_website_redirects", True], ["pop_toast_duration", 5], ["pop_toast", True], ["show_deactivated_watches", True], ["show_in_windowlist", True], ["show_notifier", True], ["show_toolbar", True], ["sort_function", "name"], ["sort_order", "asc"], ["update_sound", "/usr/share/sounds/ekiga/voicemail.wav"], ["use_update_sound", False], ["window_notifier_height", 500], ["window_notifier_width", 500] ) for default_setting in self.default_settings: if self.specto_gconf.get_entry(default_setting[0]) == None: #the key has no user-defined value or does not exist self.specto_gconf.set_entry(default_setting[0], default_setting[1]) def check_instance(self): """ Check if specto is already running. """ pidfile = os.environ['HOME'] + "/.specto/" + "specto.pid" if not os.path.exists(pidfile): f = open(pidfile, "w") f.close() os.chmod(pidfile, 0600) #see if specto is already running f=open(pidfile, "r") pid = f.readline() f.close() if pid: p=os.system("ps --no-heading --pid " + pid) p_name=os.popen("ps -f --pid " + pid).read() if p == 0 and "specto" in p_name: self.logger.log(_("Specto is already running!"), "critical", self.__class__) sys.exit(0) #write the pid file f=open(pidfile, "w") f.write(str(os.getpid())) f.close() def recreate_tray(self, *args): """ Recreate a tray icon if the notification area unexpectedly quits. """ try:self.tray.destroy() except:pass self.tray = "" self.tray = Tray(self) self.count_updated_watches() def create_all_watches(self, value_db): """ Create the watches at startup. """ for i in value_db: self.create_watch(value_db[i]) if GTK: while gtk.events_pending(): gtk.main_iteration_do(False) if self.specto_gconf.get_entry("show_deactivated_watches")== True: self.notifier.wTree.get_widget("display_all_watches").set_active(True) self.notifier.toggle_show_deactivated_watches(startup=True)#True makes startup=True, only used on the first startup to avoid duplicate watches. #start the active watches if self.notifier_initialized: self.notifier.refresh() def create_watch(self, values): """ Add a watch to the watches repository. """ id = len(self.watch_db) if values['type'] == 0: #add a website from spectlib.watch_web_static import Web_watch self.watch_db[id] = Web_watch(self, values['name'], values['refresh'], values['uri'], id, values['error_margin']) #TODO: Authentication elif values['type'] == 1: #add an email if int(values['prot']) == 0: #check if pop3, imap or gmail is used import spectlib.watch_mail_pop3 self.watch_db[id] = spectlib.watch_mail_pop3.Mail_watch(values['refresh'], values['host'], values['username'], values['password'], values['ssl'], self, id, values['name']) elif int(values['prot']) == 1: import spectlib.watch_mail_imap self.watch_db[id] = spectlib.watch_mail_imap.Mail_watch(values['refresh'], values['host'], values['username'], values['password'], values['ssl'], self, id, values['name']) else: import spectlib.watch_mail_gmail self.watch_db[id] = spectlib.watch_mail_gmail.Mail_watch(values['refresh'], values['username'], values['password'], self, id, values['name']) elif values['type'] == 2: #add a file from spectlib.watch_file import File_watch self.watch_db[id] = File_watch(values['refresh'], values['file'], values['mode'], self, id, values['name']) elif values['type'] == 3: #add a process watch from spectlib.watch_process import Process_watch self.watch_db[id] = Process_watch(values['refresh'], values['process'], self, id, values['name']) elif values['type'] == 4: #add a port watch from spectlib.watch_port import Port_watch self.watch_db[id] = Port_watch(values['refresh'], values['port'], self, id, values['name']) elif values['type'] == 5: #add a google reader account from spectlib.watch_web_greader import Google_reader self.watch_db[id] = Google_reader(values['refresh'], values['username'], values['password'], self, id, values['name']) try: self.watch_db[id].updated = values['updated'] except: self.watch_db[id].updated = False try: self.watch_db[id].active = values['active'] except: self.watch_db[id].active = True try: self.watch_db[id].last_updated = values['last_updated'] except: self.watch_db[id].last_updated = _("No updates yet.") if GTK: if not self.notifier_initialized: self.notifier = Notifier(self) #self.notifier.restore_size_and_position()#fixme: is this necessary? this makes specto output stuff for nothing. self.notifier.add_notifier_entry(values['name'], values['type'], id) try: if values['updated']: self.toggle_updated(id) except: pass try: if values['active'] == False: self.notifier.deactivate(id) except: pass return id def clear_watch(self, id): """ Mark a watch as not updated. """ new_values = {} self.watch_db[id].updated = False new_values['name'] = self.watch_db[id].name new_values['updated'] = False self.watch_io.write_options(new_values) self.count_updated_watches() def mark_watch_busy(self, progress, id): """ Display a refresh icon when updating watches. """ self.notifier.toggle_updating(progress, id) def set_status(self, id, status): """ Set the status from a watch (active/not active). """ new_values = {} new_values['name'] = self.watch_db[id].name new_values['active'] = status if status == False: new_values['updated'] = False self.watch_db[id].updated = False self.notifier.clear_watch('',id) self.watch_db[id].active = status self.watch_io.write_options(new_values) def replace_name(self, orig, new): """ Replace the name from a watch in watches.list. """ self.watch_io.replace_name(orig, new) def start_watch(self, id): """ Start a watch. """ self.notifier.toggle_updating(True, id) self.watch_db[id].start_watch() self.logger.log(_("watch \"%s\" started") % self.watch_db[id].name, "info", self.__class__) def stop_watch(self, id): """ Stop a watch. """ self.watch_db[id].stop_watch() self.logger.log(_("watch \"%s\" stopped") % self.watch_db[id].name, "info", self.__class__) def add_watch(self, values): """ Add a new watch. """ new_values = {} new_values['name'] = values['name'] new_values['type'] = values['type'] new_values['refresh'] = self.set_interval(values['refresh_value'], values['refresh_unit']) if int(values['type']) == 0: #web new_values['uri'] = values['url'] new_values['error_margin'] = values['error_margin'] elif int(values['type']) == 1: #mail if int(values['prot']) == 0 or int(values['prot']) == 1: new_values['host'] = values['host'] new_values['ssl'] = values['ssl'] new_values['username'] = values['username'] new_values['password'] = values['password'] new_values['prot'] = values['prot'] elif int(values['type']) == 2: #file new_values['file'] = values['file'] new_values['mode'] = values['mode'] elif int(values['type']) == 3: #process new_values['process'] = values['process'] elif int(values['type']) == 4: #port new_values['port'] = values['port'] elif int(values['type']) == 5: #google reader new_values['username'] = values['username'] new_values['password'] = values['password'] id = self.create_watch(new_values) self.start_watch(id) self.watch_io.write_options(new_values) def edit_watch(self, values): """ Edit a watch. """ new_values = {} new_values['name'] = values['name'] new_values['type'] = values['type'] new_values['refresh'] = self.set_interval(values['refresh_value'], values['refresh_unit']) if int(values['type']) == 0: #web new_values['uri'] = values['url'] new_values['error_margin'] = values['error_margin'] elif int(values['type']) == 1: #mail if int(values['prot']) != 2: #gmail doesn't need a host and SSL it seems, so this is updated only of it's another kind of mail watch new_values['host'] = values['host'] new_values['ssl'] = values['ssl'] new_values['username'] = values['username'] new_values['password'] = values['password'] new_values['prot'] = values['prot'] elif int(values['type']) == 2: #file new_values['file'] = values['file'] elif int(values['type']) == 3: #process new_values['process'] = values['process'] elif int(values['type']) == 4: #port new_values['port'] = values['port'] elif int(values['type']) == 5: #google reader new_values['username'] = values['username'] new_values['password'] = values['password'] self.watch_io.write_options(new_values) self.notifier.show_watch_info() def remove_watch(self, name, id): """ Remove a watch. """ try: self.stop_watch(id) except: pass del self.watch_db[id] self.count_updated_watches() self.watch_io.remove_watch(name)#do not clear the watch after removing it or it will mess up the watches.list self.notifier.model.remove(self.notifier.iter[id]) def find_watch(self, name): """ Returns the key of a watch or None if it doesn't exists. """ k = -1 for key in self.watch_db.iterkeys(): if self.watch_db[key].name == name: k = key break return k def check_unique_watch(self, name): """ Check if the watch name is unique. """ if self.watch_io.search_watch(name) and GTK: return False else: return True def count_updated_watches(self): """ Count the number of updated watches for the tooltip. """ tooltip_updated_watches = { 0:0,1:0,2:0,3:0,4:0,5:0 }#don't forget to update this if you are implementing a new type of watch for i in self.watch_db: if self.watch_db[i].updated == True: self.tray.set_icon_state_excited()#change the tray icon color to orange tooltip_updated_watches[self.watch_db[i].type] += 1 if tooltip_updated_watches.values() == [0,0,0,0,0,0]:#there are no more watches to clear, reset the tray icon self.tray.set_icon_state_normal() self.notifier.wTree.get_widget("button_clear_all").set_sensitive(False) self.tray.show_tooltip(tooltip_updated_watches) def toggle_updated(self, id): """ When a watch is updated: change name in notifier window, change the tray icon state, play a sound, ... """ new_values = {} now = datetime.today() #TODO:XXX:GETTEXT new_values['last_updated'] = now.strftime("%A %d %b %Y %H:%M") self.watch_db[id].last_updated = now.strftime("%A %d %b %Y %H:%M") self.watch_db[id].updated = True if self.notifier_initialized: self.notifier.toggle_updated(id) new_values['name'] = self.watch_db[id].name new_values['updated'] = True self.watch_io.write_options(new_values) #write the watches state in watches.list self.count_updated_watches() #show the tooltip def toggle_all_cleared(self): """ Set the state from all the watches back to 'not updated'. """ for i in self.watch_db: new_values = {} self.watch_db[i].updated = False new_values['name'] = self.watch_db[i].name new_values['updated'] = False self.watch_io.write_options(new_values) self.count_updated_watches() def set_interval(self, refresh, refresh_unit): """ Set the interval between the update checks. refresh = number refresh_unit = days, hours, minutes,... in values of 0, 1, 2, 3. """ new_refresh = 0 if refresh_unit == 0:#seconds new_refresh = refresh * 1000 elif refresh_unit == 1:#minutes new_refresh = refresh * 60 * 1000 elif refresh_unit == 2:#hours new_refresh = (refresh * 60) * 60 * 1000 elif refresh_unit == 3:#days new_refresh = ((refresh * 60) * 60) * 24 *1000 return new_refresh def get_interval(self, value): """ Get the interval between 2 updates. """ if ((value / 60) / 60) / 24 / 1000 > 0: refresh_value = ((value / 60) / 60) / 24 / 1000 type = 3 elif (value / 60) / 60 / 1000 > 0: refresh_value = (value / 60) / 60 / 1000 type = 2 elif value / 60 / 1000 > 0: refresh_value = value / 60 / 1000 type = 1 else: refresh_value = value / 1000 type = 0 return refresh_value, type def toggle_notifier(self, *args): """ Toggle the state of the notifier, hidden or shown. It will save the size, position, and the last state when you closed Specto. """ #Creating the notifier window, but keeping it hidden if not self.notifier_initialized and self.notifier_keep_hidden: self.notifier = Notifier(self) #self.notifier.restore_size_and_position()#this is NOT needed here because it already does that on instanciation on the line above -kiddo self.notifier.notifier.hide() #Creating the notifier window and displaying it elif not self.notifier_initialized and not self.notifier_keep_hidden: self.notifier = Notifier(self) #self.notifier.restore_size_and_position()#this is NOT needed here because it already does that on instanciation on the line above -kiddo self.notifier.notifier.show() elif self.notifier_initialized: if self.notifier.get_state()==True and self.notifier_keep_hidden: self.logger.log(_("notifier: reappear"), "debug", self.__class__) self.specto_gconf.set_entry("show_notifier", True) self.notifier.restore_size_and_position()#to make sure that the x and y positions don't jump around self.notifier.notifier.show() elif self.notifier.get_state()==True and not self.notifier_keep_hidden: self.logger.log(_("notifier: hide"), "debug", self.__class__) self.specto_gconf.set_entry("show_notifier", False) self.notifier.notifier.hide() else: self.logger.log(_("notifier: reappear"), "debug", self.__class__) self.specto_gconf.set_entry("show_notifier", True) self.notifier.restore_size_and_position()#to make sure that the x and y positions don't jump around self.notifier.notifier.show() self.notifier_initialized = True def show_preferences(self, *args): """ Show the preferences window. """ if not self.preferences_initialized or self.preferences.get_state() == True: self.logger.log(_("preferences: create"), "debug", self.__class__) self.pref=Preferences(self) else: self.logger.log(_("preferences: reappear"), "debug", self.__class__) self.pref.show() def show_error_log(self, *args): """ Show the error log. """ if self.error_l == "": self.error_l= Log_dialog(self) self.logger.log(_("error log: create"), "debug", self.__class__) elif self.error_l.log_dialog.flags() & gtk.MAPPED: self.logger.log(_("error log: already visible"), "debug", self.__class__) else: self.error_l= Log_dialog(self) self.logger.log(_("error log: recreate"), "debug", self.__class__) def show_add_watch(self, *args): """ Show the add watch window. """ if self.add_w == "": self.add_w= Add_watch(self) self.logger.log(_("add watch: create"), "debug", self.__class__) elif self.add_w.add_watch.flags() & gtk.MAPPED: self.logger.log(_("add watch: already visible"), "debug", self.__class__) else: self.add_w= Add_watch(self) self.logger.log(_("add watch: recreate"), "debug", self.__class__) def show_edit_watch(self, id, *args): """ Show the edit watch window. """ selected = "" if not id == -1: selected = self.watch_db[id] else: for i in self.watch_db: if self.watch_db[i].name == args[0]: selected = self.watch_db[i] if self.edit_w == "": self.edit_w= Edit_watch(self, selected) self.logger.log(_("edit watch: create"), "debug", self.__class__) elif self.edit_w.edit_watch.flags() & gtk.MAPPED: self.logger.log(_("edit watch: already visible"), "debug", self.__class__) else: self.edit_w= Edit_watch(self, selected) self.logger.log(_("edit watch: recreate"), "debug", self.__class__) def show_about(self, *args): """ Show the about window. """ if self.about == "": self.about = About(self) elif self.about.about.flags() & gtk.MAPPED: pass else: self.about = About(self) def show_help(self, *args): """ Show the help web page. """ self.util.show_webpage("http://code.google.com/p/specto/w/list") def import_export_watches(self, action): """ Show the import/export window. """ if self.export == "": self.export = Import_watch(self, action) elif self.export.import_watch.flags() & gtk.MAPPED: pass else: self.export = Import_watch(self, action) def quit(self, *args): """ Save the save and position from the notifier and quit Specto. """ if self.notifier.get_state()==True and not self.notifier_keep_hidden: self.notifier.save_size_and_position()#when quitting specto abruptly, remember the notifier window properties try: gtk.main_quit() except: #create a close dialog dialog = gtk.Dialog(_("Cannot quit yet"), None, gtk.DIALOG_MODAL | gtk.DIALOG_NO_SEPARATOR | gtk.DIALOG_DESTROY_WITH_PARENT, None) #HIG tricks dialog.set_has_separator(False) dialog.add_button(_("Murder!"), 3) dialog.add_button(gtk.STOCK_CANCEL, -1) dialog.label_hbox = gtk.HBox(spacing=6) icon = gtk.Image() icon.set_from_icon_name("dialog-warning", 64) dialog.label_hbox.pack_start(icon, True, True, 6) icon.show() label = gtk.Label(_('<b><big>Specto is currently busy and cannot quit yet.</big></b>\n\nThis may be because it is checking for watch updates.\nHowever, you can try forcing it to quit by clicking the murder button.')) label.set_use_markup(True) dialog.label_hbox.pack_start(label, True, True, 6)#here, pack means "cram the label right at the start of the vbox before the buttons" label.show() dialog.vbox.pack_start(dialog.label_hbox, True, True, 12) dialog.label_hbox.show() icon = gtk.gdk.pixbuf_new_from_file(self.PATH + 'icons/specto_window_icon.svg' ) dialog.set_icon(icon) answer = dialog.run() if answer == 3: try:#go figure, it never works! self.notifier.stop_refresh = True sys.exit(0) except: #kill the specto process with killall os.system('killall specto') else: dialog.destroy()
def __init__(self): self.DEBUG = DEBUG self.util = util self.PATH = self.util.get_path() self.LOGO_PATH = os.path.join(self.PATH, "icons/specto.svg") self.SRC_PATH = self.util.get_path("src") self.SPECTO_DIR = self.util.get_path("specto") self.CACHE_DIR = self.util.get_path("tmp") self.FILE = self.util.get_file() self.logger = Logger(self) self.VERSION = VERSION # The Specto version number self.GTK = GTK if not self.check_instance(): #see if specto is already running self.specto_gconf = specto_gconf self.check_default_settings() self.connection_manager = conmgr.get_net_listener() self.use_keyring = self.specto_gconf.get_entry("use_keyring") #create the watch collection and add the watches self.watch_db = Watch_collection(self) self.watch_io = Watch_io(self, self.FILE) if (sys.argv[1:] and "--console" in sys.argv[1:][0]) or not self.GTK: self.logger.log(_("Console mode enabled."), "debug", "specto") self.GTK = False self.CONSOLE = True try: args = sys.argv[1:][1] except: args = "" self.console = Console(self, args) elif self.GTK: self.GTK = True self.CONSOLE = False self.icon_theme = gtk.icon_theme_get_default() #allow users to hide the window on startup if sys.argv[1:] and "--no-window" in sys.argv[1:][0]: self.notifier_hide = True #always show if there's no icon and no indicator support elif self.specto_gconf.get_entry( "always_show_icon") == False and not INDICATOR: self.notifier_hide = False elif self.specto_gconf.get_entry("show_notifier") == True: self.notifier_hide = False elif self.specto_gconf.get_entry("show_notifier") == False: self.notifier_hide = True else: #just in case the entry was never created in gconf self.notifier_keep_hidden = False self.notifier = Notifier(self) else: sys.exit(0) #listen for gconf keys self.specto_gconf.notify_entry("debug_mode", self.key_changed, "debug") values = self.watch_io.read_all_watches(True) try: self.watch_db.create(values) except AttributeError as error_fields: self.logger.log(_("Could not create a watch, because it is corrupt."), \ "critical", "specto") if self.GTK: for watch in self.watch_db: self.notifier.add_notifier_entry(watch.id) # Listen for USR1. If received, answer and show the window def listen_for_USR1(signum, frame): f = open(self.SPECTO_DIR + "/" + "specto.pid.boot") pid = int(f.readline()) f.close() os.kill(pid, signal.SIGUSR1) # If window was not shown, make it appear if not self.notifier.get_state(): self.logger.log( "Showing window, the user ran another instance of specto", "debug", "specto") self.toggle_notifier() else: # Based on http://www.pygtk.org/docs/pygtk/class-gtkwindow.html#method-gtkwindow--present self.logger.log( "Window is already visible! Raising it to the front.", "debug", "specto") self.notifier.notifier.present() signal.signal(signal.SIGUSR1, listen_for_USR1) self.notifier.refresh_all_watches() else: self.console.start_watches() if self.GTK: gtk.main() else: try: self.go = gobject.MainLoop() self.go.run() except (KeyboardInterrupt, SystemExit): sys.exit(0)
class Specto: """ The main Specto class. """ def __init__(self): self.DEBUG = DEBUG self.util = util self.PATH = self.util.get_path() self.LOGO_PATH = os.path.join(self.PATH, "icons/specto.svg") self.SRC_PATH = self.util.get_path("src") self.SPECTO_DIR = self.util.get_path("specto") self.CACHE_DIR = self.util.get_path("tmp") self.FILE = self.util.get_file() self.logger = Logger(self) self.VERSION = VERSION # The Specto version number self.GTK = GTK if not self.check_instance(): #see if specto is already running self.specto_gconf = specto_gconf self.check_default_settings() self.connection_manager = conmgr.get_net_listener() self.use_keyring = self.specto_gconf.get_entry("use_keyring") #create the watch collection and add the watches self.watch_db = Watch_collection(self) self.watch_io = Watch_io(self, self.FILE) if (sys.argv[1:] and "--console" in sys.argv[1:][0]) or not self.GTK: self.logger.log(_("Console mode enabled."), "debug", "specto") self.GTK = False self.CONSOLE = True try: args = sys.argv[1:][1] except: args = "" self.console = Console(self, args) elif self.GTK: self.GTK = True self.CONSOLE = False self.icon_theme = gtk.icon_theme_get_default() #allow users to hide the window on startup if sys.argv[1:] and "--no-window" in sys.argv[1:][0]: self.notifier_hide = True #always show if there's no icon and no indicator support elif self.specto_gconf.get_entry( "always_show_icon") == False and not INDICATOR: self.notifier_hide = False elif self.specto_gconf.get_entry("show_notifier") == True: self.notifier_hide = False elif self.specto_gconf.get_entry("show_notifier") == False: self.notifier_hide = True else: #just in case the entry was never created in gconf self.notifier_keep_hidden = False self.notifier = Notifier(self) else: sys.exit(0) #listen for gconf keys self.specto_gconf.notify_entry("debug_mode", self.key_changed, "debug") values = self.watch_io.read_all_watches(True) try: self.watch_db.create(values) except AttributeError as error_fields: self.logger.log(_("Could not create a watch, because it is corrupt."), \ "critical", "specto") if self.GTK: for watch in self.watch_db: self.notifier.add_notifier_entry(watch.id) # Listen for USR1. If received, answer and show the window def listen_for_USR1(signum, frame): f = open(self.SPECTO_DIR + "/" + "specto.pid.boot") pid = int(f.readline()) f.close() os.kill(pid, signal.SIGUSR1) # If window was not shown, make it appear if not self.notifier.get_state(): self.logger.log( "Showing window, the user ran another instance of specto", "debug", "specto") self.toggle_notifier() else: # Based on http://www.pygtk.org/docs/pygtk/class-gtkwindow.html#method-gtkwindow--present self.logger.log( "Window is already visible! Raising it to the front.", "debug", "specto") self.notifier.notifier.present() signal.signal(signal.SIGUSR1, listen_for_USR1) self.notifier.refresh_all_watches() else: self.console.start_watches() if self.GTK: gtk.main() else: try: self.go = gobject.MainLoop() self.go.run() except (KeyboardInterrupt, SystemExit): sys.exit(0) def key_changed(self, *args): """ Listen for gconf keys. """ label = args[3] if label == "debug": self.DEBUG = self.specto_gconf.get_entry("debug_mode") def check_default_settings(self): """ This is used to set the default settings properly the first time Specto is run, without using gconf schemas """ #check if the ekiga sounds exists if os.path.exists("/usr/share/sounds/ekiga/voicemail.wav"): changed_sound = "/usr/share/sounds/ekiga/voicemail.wav" else: changed_sound = "" self.default_settings = ( ["always_show_icon", False], #True would be against the HIG! ["debug_mode", False], ["follow_website_redirects", True], ["pop_toast", True], ["show_deactivated_watches", True], ["show_notifier", True], ["show_toolbar", True], ["sort_function", "name"], ["sort_order", "asc"], ["changed_sound", changed_sound], ["use_changed_sound", False], ["window_notifier_height", 500], ["window_notifier_width", 500], ["use_keyring", True]) for default_setting in self.default_settings: if self.specto_gconf.get_entry(default_setting[0]) == None: self.specto_gconf.set_entry(default_setting[0], \ default_setting[1]) def check_instance(self): """ Check if specto is already running. """ pidfile = self.SPECTO_DIR + "/" + "specto.pid" if not os.path.exists(pidfile): f = open(pidfile, "w") f.close() os.chmod(pidfile, stat.S_IWUSR | stat.S_IRUSR) #see if specto is already running with open(pidfile, "r") as f: pid = f.readline() if pid: p = os.system("ps --no-heading --pid " + pid) p_name = os.popen("ps -f --pid " + pid).read() if p == 0 and "specto" in p_name: if self.GTK: # Save our pid and prepare a 'pong' system f = open(pidfile + ".boot", "w") f.write(str(os.getpid())) f.close() def not_responding(signum, frame): """ Launch the already running dialog if the other instance doesn't respond """ os.unlink(pidfile + ".boot") self.already_running_dialog() def response_received(signum, frame): """ Kill this specto if the other one answers """ signal.alarm(0) os.unlink(pidfile + ".boot") self.logger.log( "Specto is already running! The old instance will be brought to front.", "debug", "specto") sys.exit(0) signal.signal(signal.SIGALRM, not_responding) signal.signal(signal.SIGUSR1, response_received) signal.alarm(5) # Send signal to raise window os.kill(int(pid), signal.SIGUSR1) # Wait for signals signal.pause() return True elif DEBUG: self.logger.log(_("Specto is already running!"), "critical", "specto") sys.exit(0) else: print(_("Specto is already running!")) sys.exit(0) #write the pid file with open(pidfile, "w") as f: f.write(str(os.getpid())) def mark_watch_status(self, status, id): """ get the watch status (checking, changed, idle) """ if self.GTK: self.notifier.mark_watch_status(status, id) elif self.CONSOLE: self.console.mark_watch_status(status, id) def toggle_notifier(self, *args): """ Toggle the state of the notifier, hidden or shown. It will save the size, position, and the last state when you closed Specto. """ #Creating the notifier window, but keeping it hidden if self.notifier.get_state() == True and not self.notifier_hide: self.specto_gconf.set_entry("show_notifier", True) self.notifier.restore_size_and_position() self.notifier.notifier.show() self.notifier_hide = True elif self.notifier.get_state() == True and self.notifier_hide: self.notifier.save_size_and_position() self.specto_gconf.set_entry("show_notifier", False) self.notifier.notifier.hide() self.notifier_hide = False else: self.specto_gconf.set_entry("show_notifier", True) self.notifier.restore_size_and_position() self.notifier.notifier.show() self.notifier_hide = True def quit(self, *args): """ Save the save and position from the notifier and quit Specto. """ if self.notifier.get_state() == True and self.notifier_hide: self.notifier.save_size_and_position() try: gtk.main_quit() except: #create a close dialog self.dialog = gtk.Dialog( _("Cannot quit yet"), None, gtk.DIALOG_NO_SEPARATOR | gtk.DIALOG_DESTROY_WITH_PARENT, None) self.dialog.set_modal( False ) # Needed to prevent the notifier UI and refresh process from blocking. Also, do not use dialog.run(), because it automatically sets modal to true. #HIG tricks self.dialog.set_has_separator(False) self.dialog.add_button(_("Murder!"), 3) self.dialog.add_button(gtk.STOCK_CANCEL, -1) self.dialog.label_hbox = gtk.HBox(spacing=6) icon = gtk.Image() icon.set_from_pixbuf(self.icon_theme.\ load_icon("dialog-warning", 64, 0)) self.dialog.label_hbox.pack_start(icon, True, True, 6) icon.show() label = gtk.Label( _('<b><big>Specto is currently busy and cannot quit yet.</big></b>\n\nThis may be because it is checking for watch changes.\nHowever, you can try forcing it to quit by clicking the murder button.' )) label.set_use_markup(True) self.dialog.label_hbox.pack_start(label, True, True, 6) label.show() self.dialog.vbox.pack_start(self.dialog.label_hbox, True, True, 12) self.dialog.label_hbox.show() self.dialog.set_icon_from_file(self.LOGO_PATH) self.dialog.connect("delete_event", self.quit_dialog_response) self.dialog.connect("response", self.quit_dialog_response) self.dialog.show_all() def quit_dialog_response(self, widget, answer): if answer == 3: try: #go figure, it never works! self.notifier.stop_refresh = True sys.exit(0) except: #kill the specto process with killall os.system('killall specto') else: self.dialog.hide() def already_running_dialog(self, *args): """ Save the save and position from the notifier and quit Specto. """ #create a dialog self.dialog = gtk.Dialog( _("Error"), None, gtk.DIALOG_NO_SEPARATOR | gtk.DIALOG_DESTROY_WITH_PARENT, None) self.dialog.set_modal( False ) # Needed to prevent the notifier UI and refresh process from blocking. Also, do not use dialog.run(), because it automatically sets modal to true. #HIG tricks self.dialog.set_has_separator(False) #self.dialog.add_button(_("Murder!"), 3) self.dialog.add_button(gtk.STOCK_OK, 3) self.dialog.label_hbox = gtk.HBox(spacing=6) icon = gtk.Image() icon.set_from_stock(gtk.STOCK_DIALOG_INFO, gtk.ICON_SIZE_DIALOG) self.dialog.label_hbox.pack_start(icon, True, True, 6) icon.show() label = gtk.Label(_('Specto is already running!')) label.set_use_markup(True) self.dialog.label_hbox.pack_start(label, True, True, 6) label.show() self.dialog.vbox.pack_start(self.dialog.label_hbox, True, True, 12) self.dialog.label_hbox.show() self.dialog.set_icon_from_file(self.LOGO_PATH) self.dialog.connect("delete_event", self.running_dialog_response) self.dialog.connect("response", self.running_dialog_response) self.dialog.show_all() def running_dialog_response(self, widget, answer): if answer == 3: sys.exit(0)
def __init__(self): self.DEBUG = DEBUG self.util = util self.PATH = self.util.get_path() self.LOGO_PATH = os.path.join(self.PATH, "icons/specto.svg") self.SRC_PATH = self.util.get_path("src") self.SPECTO_DIR = self.util.get_path("specto") self.CACHE_DIR = self.util.get_path("tmp") self.FILE = self.util.get_file() self.logger = Logger(self) self.VERSION = VERSION # The Specto version number self.GTK = GTK if not self.check_instance(): #see if specto is already running self.specto_gconf = specto_gconf self.check_default_settings() self.connection_manager = conmgr.get_net_listener() self.use_keyring = self.specto_gconf.get_entry("use_keyring") #create the watch collection and add the watches self.watch_db = Watch_collection(self) self.watch_io = Watch_io(self, self.FILE) if (sys.argv[1:] and "--console" in sys.argv[1:][0]) or not self.GTK: self.logger.log(_("Console mode enabled."), "debug", "specto") self.GTK = False self.CONSOLE = True try: args = sys.argv[1:][1] except: args = "" self.console = Console(self, args) elif self.GTK: self.GTK = True self.CONSOLE = False self.icon_theme = gtk.icon_theme_get_default() #allow users to hide the window on startup if sys.argv[1:] and "--no-window" in sys.argv[1:][0]: self.notifier_hide = True #always show if there's no icon and no indicator support elif self.specto_gconf.get_entry("always_show_icon") == False and not INDICATOR: self.notifier_hide = False elif self.specto_gconf.get_entry("show_notifier")==True: self.notifier_hide = False elif self.specto_gconf.get_entry("show_notifier")==False: self.notifier_hide = True else:#just in case the entry was never created in gconf self.notifier_keep_hidden = False self.notifier = Notifier(self) else: sys.exit(0) #listen for gconf keys self.specto_gconf.notify_entry("debug_mode", self.key_changed, "debug") values = self.watch_io.read_all_watches(True) try: self.watch_db.create(values) except AttributeError as error_fields: self.logger.log(_("Could not create a watch, because it is corrupt."), \ "critical", "specto") if self.GTK: for watch in self.watch_db: self.notifier.add_notifier_entry(watch.id) # Listen for USR1. If received, answer and show the window def listen_for_USR1(signum, frame): f = open(self.SPECTO_DIR + "/" + "specto.pid.boot") pid = int(f.readline()) f.close() os.kill(pid, signal.SIGUSR1) # If window was not shown, make it appear if not self.notifier.get_state(): self.logger.log("Showing window, the user ran another instance of specto", "debug", "specto") self.toggle_notifier() else: # Based on http://www.pygtk.org/docs/pygtk/class-gtkwindow.html#method-gtkwindow--present self.logger.log("Window is already visible! Raising it to the front.", "debug", "specto") self.notifier.notifier.present() signal.signal(signal.SIGUSR1, listen_for_USR1) self.notifier.refresh_all_watches() else: self.console.start_watches() if self.GTK: gtk.main() else: try: self.go = gobject.MainLoop() self.go.run() except (KeyboardInterrupt, SystemExit): sys.exit(0)
class Specto: """ The main Specto class. """ def __init__(self): self.DEBUG = DEBUG self.util = util self.PATH = self.util.get_path() self.LOGO_PATH = os.path.join(self.PATH, "icons/specto.svg") self.SRC_PATH = self.util.get_path("src") self.SPECTO_DIR = self.util.get_path("specto") self.CACHE_DIR = self.util.get_path("tmp") self.FILE = self.util.get_file() self.logger = Logger(self) self.VERSION = VERSION # The Specto version number self.GTK = GTK if not self.check_instance(): #see if specto is already running self.specto_gconf = specto_gconf self.check_default_settings() self.connection_manager = conmgr.get_net_listener() self.use_keyring = self.specto_gconf.get_entry("use_keyring") #create the watch collection and add the watches self.watch_db = Watch_collection(self) self.watch_io = Watch_io(self, self.FILE) if (sys.argv[1:] and "--console" in sys.argv[1:][0]) or not self.GTK: self.logger.log(_("Console mode enabled."), "debug", "specto") self.GTK = False self.CONSOLE = True try: args = sys.argv[1:][1] except: args = "" self.console = Console(self, args) elif self.GTK: self.GTK = True self.CONSOLE = False self.icon_theme = gtk.icon_theme_get_default() #allow users to hide the window on startup if sys.argv[1:] and "--no-window" in sys.argv[1:][0]: self.notifier_hide = True #always show if there's no icon and no indicator support elif self.specto_gconf.get_entry("always_show_icon") == False and not INDICATOR: self.notifier_hide = False elif self.specto_gconf.get_entry("show_notifier")==True: self.notifier_hide = False elif self.specto_gconf.get_entry("show_notifier")==False: self.notifier_hide = True else:#just in case the entry was never created in gconf self.notifier_keep_hidden = False self.notifier = Notifier(self) else: sys.exit(0) #listen for gconf keys self.specto_gconf.notify_entry("debug_mode", self.key_changed, "debug") values = self.watch_io.read_all_watches(True) try: self.watch_db.create(values) except AttributeError as error_fields: self.logger.log(_("Could not create a watch, because it is corrupt."), \ "critical", "specto") if self.GTK: for watch in self.watch_db: self.notifier.add_notifier_entry(watch.id) # Listen for USR1. If received, answer and show the window def listen_for_USR1(signum, frame): f = open(self.SPECTO_DIR + "/" + "specto.pid.boot") pid = int(f.readline()) f.close() os.kill(pid, signal.SIGUSR1) # If window was not shown, make it appear if not self.notifier.get_state(): self.logger.log("Showing window, the user ran another instance of specto", "debug", "specto") self.toggle_notifier() else: # Based on http://www.pygtk.org/docs/pygtk/class-gtkwindow.html#method-gtkwindow--present self.logger.log("Window is already visible! Raising it to the front.", "debug", "specto") self.notifier.notifier.present() signal.signal(signal.SIGUSR1, listen_for_USR1) self.notifier.refresh_all_watches() else: self.console.start_watches() if self.GTK: gtk.main() else: try: self.go = gobject.MainLoop() self.go.run() except (KeyboardInterrupt, SystemExit): sys.exit(0) def key_changed(self, *args): """ Listen for gconf keys. """ label = args[3] if label == "debug": self.DEBUG = self.specto_gconf.get_entry("debug_mode") def check_default_settings(self): """ This is used to set the default settings properly the first time Specto is run, without using gconf schemas """ #check if the ekiga sounds exists if os.path.exists("/usr/share/sounds/ekiga/voicemail.wav"): changed_sound = "/usr/share/sounds/ekiga/voicemail.wav" else: changed_sound = "" self.default_settings = ( ["always_show_icon", False], #True would be against the HIG! ["debug_mode", False], ["follow_website_redirects", True], ["pop_toast", True], ["show_deactivated_watches", True], ["show_notifier", True], ["show_toolbar", True], ["sort_function", "name"], ["sort_order", "asc"], ["changed_sound", changed_sound], ["use_changed_sound", False], ["window_notifier_height", 500], ["window_notifier_width", 500], ["use_keyring", True]) for default_setting in self.default_settings: if self.specto_gconf.get_entry(default_setting[0]) == None: self.specto_gconf.set_entry(default_setting[0], \ default_setting[1]) def check_instance(self): """ Check if specto is already running. """ pidfile = self.SPECTO_DIR + "/" + "specto.pid" if not os.path.exists(pidfile): f = open(pidfile, "w") f.close() os.chmod(pidfile, stat.S_IWUSR | stat.S_IRUSR) #see if specto is already running with open(pidfile, "r") as f: pid = f.readline() if pid: p = os.system("ps --no-heading --pid " + pid) p_name = os.popen("ps -f --pid " + pid).read() if p == 0 and "specto" in p_name: if self.GTK: # Save our pid and prepare a 'pong' system f = open(pidfile + ".boot", "w") f.write(str(os.getpid())) f.close() def not_responding(signum, frame): """ Launch the already running dialog if the other instance doesn't respond """ os.unlink(pidfile + ".boot") self.already_running_dialog() def response_received(signum, frame): """ Kill this specto if the other one answers """ signal.alarm(0) os.unlink(pidfile + ".boot") self.logger.log("Specto is already running! The old instance will be brought to front.", "debug", "specto") sys.exit(0) signal.signal(signal.SIGALRM, not_responding) signal.signal(signal.SIGUSR1, response_received) signal.alarm(5) # Send signal to raise window os.kill(int(pid), signal.SIGUSR1) # Wait for signals signal.pause() return True elif DEBUG: self.logger.log(_("Specto is already running!"), "critical", "specto") sys.exit(0) else: print (_("Specto is already running!")) sys.exit(0) #write the pid file with open(pidfile, "w") as f: f.write(str(os.getpid())) def mark_watch_status(self, status, id): """ get the watch status (checking, changed, idle) """ if self.GTK: self.notifier.mark_watch_status(status, id) elif self.CONSOLE: self.console.mark_watch_status(status, id) def toggle_notifier(self, *args): """ Toggle the state of the notifier, hidden or shown. It will save the size, position, and the last state when you closed Specto. """ #Creating the notifier window, but keeping it hidden if self.notifier.get_state() == True and not self.notifier_hide: self.specto_gconf.set_entry("show_notifier", True) self.notifier.restore_size_and_position() self.notifier.notifier.show() self.notifier_hide = True elif self.notifier.get_state()==True and self.notifier_hide: self.notifier.save_size_and_position() self.specto_gconf.set_entry("show_notifier", False) self.notifier.notifier.hide() self.notifier_hide = False else: self.specto_gconf.set_entry("show_notifier", True) self.notifier.restore_size_and_position() self.notifier.notifier.show() self.notifier_hide = True def quit(self, *args): """ Save the save and position from the notifier and quit Specto. """ if self.notifier.get_state() == True and self.notifier_hide: self.notifier.save_size_and_position() try: gtk.main_quit() except: #create a close dialog self.dialog = gtk.Dialog(_("Cannot quit yet"), None, gtk.DIALOG_NO_SEPARATOR | gtk.DIALOG_DESTROY_WITH_PARENT, None) self.dialog.set_modal(False) # Needed to prevent the notifier UI and refresh process from blocking. Also, do not use dialog.run(), because it automatically sets modal to true. #HIG tricks self.dialog.set_has_separator(False) self.dialog.add_button(_("Murder!"), 3) self.dialog.add_button(gtk.STOCK_CANCEL, -1) self.dialog.label_hbox = gtk.HBox(spacing=6) icon = gtk.Image() icon.set_from_pixbuf(self.icon_theme.\ load_icon("dialog-warning", 64, 0)) self.dialog.label_hbox.pack_start(icon, True, True, 6) icon.show() label = gtk.Label(_('<b><big>Specto is currently busy and cannot quit yet.</big></b>\n\nThis may be because it is checking for watch changes.\nHowever, you can try forcing it to quit by clicking the murder button.')) label.set_use_markup(True) self.dialog.label_hbox.pack_start(label, True, True, 6) label.show() self.dialog.vbox.pack_start(self.dialog.label_hbox, True, True, 12) self.dialog.label_hbox.show() self.dialog.set_icon_from_file(self.LOGO_PATH) self.dialog.connect("delete_event", self.quit_dialog_response) self.dialog.connect("response", self.quit_dialog_response) self.dialog.show_all() def quit_dialog_response(self, widget, answer): if answer == 3: try:#go figure, it never works! self.notifier.stop_refresh = True sys.exit(0) except: #kill the specto process with killall os.system('killall specto') else: self.dialog.hide() def already_running_dialog(self, *args): """ Save the save and position from the notifier and quit Specto. """ #create a dialog self.dialog = gtk.Dialog(_("Error"), None, gtk.DIALOG_NO_SEPARATOR | gtk.DIALOG_DESTROY_WITH_PARENT, None) self.dialog.set_modal(False) # Needed to prevent the notifier UI and refresh process from blocking. Also, do not use dialog.run(), because it automatically sets modal to true. #HIG tricks self.dialog.set_has_separator(False) #self.dialog.add_button(_("Murder!"), 3) self.dialog.add_button(gtk.STOCK_OK, 3) self.dialog.label_hbox = gtk.HBox(spacing=6) icon = gtk.Image() icon.set_from_stock(gtk.STOCK_DIALOG_INFO, gtk.ICON_SIZE_DIALOG) self.dialog.label_hbox.pack_start(icon, True, True, 6) icon.show() label = gtk.Label(_('Specto is already running!')) label.set_use_markup(True) self.dialog.label_hbox.pack_start(label, True, True, 6) label.show() self.dialog.vbox.pack_start(self.dialog.label_hbox, True, True, 12) self.dialog.label_hbox.show() self.dialog.set_icon_from_file(self.LOGO_PATH) self.dialog.connect("delete_event", self.running_dialog_response) self.dialog.connect("response", self.running_dialog_response) self.dialog.show_all() def running_dialog_response(self, widget, answer): if answer == 3: sys.exit(0)