more comments - support for animated gif

This commit is contained in:
Yann Leboulanger 2004-01-20 12:46:27 +00:00
parent 0e97426544
commit 6b10f27450
2 changed files with 111 additions and 35 deletions

View File

@ -106,7 +106,7 @@ class GajimCore:
if self.connected == 1: if self.connected == 1:
self.connected = 0 self.connected = 0
self.con.disconnect() self.con.disconnect()
# self.con.disconnect() self.hub.sendPlugin('STATUS', 'offline')
# END disconenctedCB # END disconenctedCB
def connect(self, account): def connect(self, account):

View File

@ -389,8 +389,8 @@ class add:
def on_subscribe(self, widget): def on_subscribe(self, widget):
"""When Subscribe button is clicked""" """When Subscribe button is clicked"""
who = self.xml.get_widget("entry_who").get_text() who = self.entry_who.get_text()
buf = self.xml.get_widget("textview_sub").get_buffer() buf = self.textview_sub.get_buffer()
start_iter = buf.get_start_iter() start_iter = buf.get_start_iter()
end_iter = buf.get_end_iter() end_iter = buf.get_end_iter()
txt = buf.get_text(start_iter, end_iter, 0) txt = buf.get_text(start_iter, end_iter, 0)
@ -400,8 +400,10 @@ class add:
def __init__(self, roster, jid=None): def __init__(self, roster, jid=None):
self.r = roster self.r = roster
xml = gtk.glade.XML('plugins/gtkgui/gtkgui.glade', 'Add') xml = gtk.glade.XML('plugins/gtkgui/gtkgui.glade', 'Add')
self.entry_who = xml.get_widget('entry_who')
self.textview_sub = xml.get_widget("textview_sub")
if jid: if jid:
xml.get_widget('entry_who').set_text(jid) self.entry_who.set_text(jid)
self.Wadd = xml.get_widget("Add") self.Wadd = xml.get_widget("Add")
xml.signal_connect('gtk_widget_destroy', self.delete_event) xml.signal_connect('gtk_widget_destroy', self.delete_event)
xml.signal_connect('on_button_sub_clicked', self.on_subscribe) xml.signal_connect('on_button_sub_clicked', self.on_subscribe)
@ -593,11 +595,15 @@ class accounts:
self.init_accounts() self.init_accounts()
class confirm: class confirm:
"""Class for confirmation window :
window that appears to confirm the removal of a contact"""
def delete_event(self, widget): def delete_event(self, widget):
"""close window""" """close window"""
self.window.destroy() self.window.destroy()
def req_usub(self, widget): def req_usub(self, widget):
"""When Ok button is clicked :
Send a message to the core to remove the user and remove it from the roster"""
model = self.r.tree.get_model() model = self.r.tree.get_model()
jid = model.get_value(self.iter, 2) jid = model.get_value(self.iter, 2)
self.r.queueOUT.put(('UNSUB', jid)) self.r.queueOUT.put(('UNSUB', jid))
@ -616,17 +622,21 @@ class confirm:
xml.signal_connect('gtk_widget_destroy', self.delete_event) xml.signal_connect('gtk_widget_destroy', self.delete_event)
class authorize: class authorize:
"""Class for authorization window :
window that appears when a user wants to add us to his/her roster"""
def delete_event(self, widget): def delete_event(self, widget):
"""close window""" """close window"""
self.window.destroy() self.window.destroy()
def auth(self, widget): def auth(self, widget):
"""Accept the request"""
self.r.queueOUT.put(('AUTH', self.jid)) self.r.queueOUT.put(('AUTH', self.jid))
self.delete_event(self) self.delete_event(self)
if not self.r.l_contact.has_key(self.jid): if not self.r.l_contact.has_key(self.jid):
add(self.r, self.jid) add(self.r, self.jid)
def deny(self, widget): def deny(self, widget):
"""refuse the request"""
self.r.queueOUT.put(('DENY', self.jid)) self.r.queueOUT.put(('DENY', self.jid))
self.delete_event(self) self.delete_event(self)
@ -641,11 +651,14 @@ class authorize:
xml.signal_connect('on_button_close_clicked', self.delete_event) xml.signal_connect('on_button_close_clicked', self.delete_event)
class agent_reg: class agent_reg:
"""Class for agent registration window :
window that appears when we want to subscribe to an agent"""
def delete_event(self, widget): def delete_event(self, widget):
"""close window""" """close window"""
self.window.destroy() self.window.destroy()
def draw_table(self): def draw_table(self):
"""Draw the table in the window"""
nbrow = 0 nbrow = 0
for name in self.infos.keys(): for name in self.infos.keys():
if name != 'key' and name != 'instructions' and name != 'x': if name != 'key' and name != 'instructions' and name != 'x':
@ -662,6 +675,8 @@ class agent_reg:
self.table.show_all() self.table.show_all()
def on_ok(self, widget): def on_ok(self, widget):
"""When Ok button is clicked :
send registration info to the core"""
for name in self.entries.keys(): for name in self.entries.keys():
self.infos[name] = self.entries[name].get_text() self.infos[name] = self.entries[name].get_text()
self.r.queueOUT.put(('REG_AGENT', self.agent)) self.r.queueOUT.put(('REG_AGENT', self.agent))
@ -683,6 +698,8 @@ class agent_reg:
xml.signal_connect('on_button_ok_clicked', self.on_ok) xml.signal_connect('on_button_ok_clicked', self.on_ok)
class browser: class browser:
"""Class for rbowser agent window :
to know the agents on the selected server"""
def delete_event(self, widget): def delete_event(self, widget):
"""close window""" """close window"""
global Wbrowser global Wbrowser
@ -690,19 +707,26 @@ class browser:
self.window.destroy() self.window.destroy()
def browse(self): def browse(self):
"""Send a request to the core to know the available agents"""
self.r.queueOUT.put(('REQ_AGENTS', None)) self.r.queueOUT.put(('REQ_AGENTS', None))
def agents(self, agents): def agents(self, agents):
"""When list of available agent arrive :
Fill the treeview with it"""
model = self.treeview.get_model() model = self.treeview.get_model()
for jid in agents.keys(): for jid in agents.keys():
iter = model.append() iter = model.append()
model.set(iter, 0, agents[jid]['name'], 1, agents[jid]['service']) model.set(iter, 0, agents[jid]['name'], 1, agents[jid]['service'])
def on_refresh(self, widget): def on_refresh(self, widget):
"""When refresh button is clicked :
refresh list : clear and rerequest it"""
self.treeview.get_model().clear() self.treeview.get_model().clear()
self.browse() self.browse()
def on_row_activated(self, widget, path, col=0): def on_row_activated(self, widget, path, col=0):
"""When a row is activated :
Ask specific informations about the selected agent and close the window"""
model = self.treeview.get_model() model = self.treeview.get_model()
iter = model.get_iter(path) iter = model.get_iter(path)
service = model.get_value(iter, 1) service = model.get_value(iter, 1)
@ -731,12 +755,17 @@ class browser:
self.browse() self.browse()
class message: class message:
"""Class for chat window"""
def delete_event(self, widget): def delete_event(self, widget):
"""close window""" """close window"""
del self.r.tab_messages[self.user.jid] del self.r.tab_messages[self.user.jid]
self.window.destroy() self.window.destroy()
def print_conversation(self, txt, contact = None, tim = None): def print_conversation(self, txt, contact = None, tim = None):
"""Print a line in the conversation :
if contact is set to status : it's a status message
if contact is set to another value : it's an outgoing message
if contact is not set : it's an incomming message"""
buffer = self.conversation.get_buffer() buffer = self.conversation.get_buffer()
if not txt: if not txt:
txt = "" txt = ""
@ -754,10 +783,12 @@ class message:
else: else:
buffer.insert_with_tags_by_name(end_iter, '<' + self.user.name + '> ', 'incoming') buffer.insert_with_tags_by_name(end_iter, '<' + self.user.name + '> ', 'incoming')
buffer.insert(end_iter, txt+'\n') buffer.insert(end_iter, txt+'\n')
#scroll to the end of the textview
self.conversation.scroll_to_mark(\ self.conversation.scroll_to_mark(\
buffer.get_mark('end'), 0.1, 0, 0, 0) buffer.get_mark('end'), 0.1, 0, 0, 0)
def read_queue(self, q): def read_queue(self, q):
"""read queue and print messages containted in it"""
while not q.empty(): while not q.empty():
evt = q.get() evt = q.get()
self.print_conversation(evt[0], tim = evt[1]) self.print_conversation(evt[0], tim = evt[1])
@ -767,6 +798,8 @@ class message:
self.r.tree.get_model().set_value(i, 0, self.r.pixbufs[self.user.show]) self.r.tree.get_model().set_value(i, 0, self.r.pixbufs[self.user.show])
def on_msg_key_press_event(self, widget, event): def on_msg_key_press_event(self, widget, event):
"""When a key is pressed :
if enter is pressed without the shit key, message (if not empty) is sent and printed in the conversation"""
if event.keyval == gtk.keysyms.Return: if event.keyval == gtk.keysyms.Return:
if (event.state & gtk.gdk.SHIFT_MASK): if (event.state & gtk.gdk.SHIFT_MASK):
return 0 return 0
@ -783,6 +816,8 @@ class message:
return 0 return 0
def on_clear(self, widget): def on_clear(self, widget):
"""When clear button is pressed :
clear the conversation"""
buffer = self.conversation.get_buffer() buffer = self.conversation.get_buffer()
deb, end = buffer.get_bounds() deb, end = buffer.get_bounds()
buffer.delete(deb, end) buffer.delete(deb, end)
@ -824,11 +859,9 @@ class message:
self.tagStatus.set_property("foreground", color) self.tagStatus.set_property("foreground", color)
class roster: class roster:
def get_icon_pixbuf(self, stock): """Class for main gtk window"""
return self.tree.render_icon(stock, size = gtk.ICON_SIZE_MENU, detail = None)
def add_user(self, u): def add_user(self, u):
""" add a ligne to the roster """ """Add a user to the roster and add groups if they aren't in roster"""
newgrp = 0 newgrp = 0
self.l_contact[u.jid] = {'user': u, 'iter': []} self.l_contact[u.jid] = {'user': u, 'iter': []}
if u.groups == []: if u.groups == []:
@ -859,6 +892,7 @@ class roster:
self.tree.expand_row(model.get_path(iterG), FALSE) self.tree.expand_row(model.get_path(iterG), FALSE)
def redraw_roster(self): def redraw_roster(self):
"""clear l_contact and l_group's iter and redraw roster"""
for j in self.l_contact.keys(): for j in self.l_contact.keys():
self.l_contact[j]['iter'] = [] self.l_contact[j]['iter'] = []
for g in self.l_group.keys(): for g in self.l_group.keys():
@ -866,11 +900,13 @@ class roster:
self.draw_roster() self.draw_roster()
def draw_roster(self): def draw_roster(self):
"""Clear and draw roster"""
self.tree.get_model().clear() self.tree.get_model().clear()
for j in self.l_contact.keys(): for j in self.l_contact.keys():
self.add_user(self.l_contact[j]['user']) self.add_user(self.l_contact[j]['user'])
def mklists(self, tab): def mklists(self, tab):
"""fill l_contact and l_group"""
for jid in tab.keys(): for jid in tab.keys():
#remove ressource from jid string #remove ressource from jid string
ji = string.split(jid, '/')[0] ji = string.split(jid, '/')[0]
@ -889,21 +925,23 @@ class roster:
if not i in self.l_group.keys(): if not i in self.l_group.keys():
self.l_group[i] = {'iter':None, 'hide':False} self.l_group[i] = {'iter':None, 'hide':False}
def update_iter(self, widget, path, iter, data): # def update_iter(self, widget, path, iter, data):
model = self.tree.get_model() # """remove or change icon of iter"""
jid = model.get_value(iter, 2) # model = self.tree.get_model()
if jid == data[0]: # jid = model.get_value(iter, 2)
if data[1] == 'offline': # if jid == data[0]:
model.remove(iter) # if data[1] == 'offline':
if not self.showOffline: # model.remove(iter)
self.found = 1 # if not self.showOffline:
else: # self.found = 1
model.set_value(iter, 0, self.pixbufs[data[1]]) # else:
self.found = 1 # model.set_value(iter, 0, self.pixbufs[data[1]])
return 1 # self.found = 1
return 0 # return 1
# return 0
def chg_status(self, jid, show, status): def chg_status(self, jid, show, status):
"""When a user change his status remove or change its icon"""
u = self.l_contact[jid]['user'] u = self.l_contact[jid]['user']
if self.l_contact[jid]['iter'] == []: if self.l_contact[jid]['iter'] == []:
self.add_user(u) self.add_user(u)
@ -931,9 +969,11 @@ class roster:
u.status = status u.status = status
def on_info(self, widget, jid): def on_info(self, widget, jid):
"""Call info_user class to display user's information"""
info_user(self.l_contact[jid]['user'], self) info_user(self.l_contact[jid]['user'], self)
def mk_menu_c(self, event, iter): def mk_menu_c(self, event, iter):
"""Make user's popup menu"""
model = self.tree.get_model() model = self.tree.get_model()
jid = model.get_value(iter, 2) jid = model.get_value(iter, 2)
path = model.get_path(iter) path = model.get_path(iter)
@ -974,6 +1014,7 @@ class roster:
self.menu_c.show_all() self.menu_c.show_all()
def mk_menu_g(self, event): def mk_menu_g(self, event):
"""Make group's popup menu"""
self.menu_c = gtk.Menu() self.menu_c = gtk.Menu()
item = gtk.MenuItem("grp1") item = gtk.MenuItem("grp1")
self.menu_c.append(item) self.menu_c.append(item)
@ -985,6 +1026,7 @@ class roster:
self.menu_c.show_all() self.menu_c.show_all()
def authorize(self, widget, jid): def authorize(self, widget, jid):
"""Authorize a user"""
self.queueOUT.put(('AUTH', jid)) self.queueOUT.put(('AUTH', jid))
# def rename(self, widget, jid, name): # def rename(self, widget, jid, name):
@ -994,12 +1036,14 @@ class roster:
# self.tree.get_model().set_value(i, 1, name) # self.tree.get_model().set_value(i, 1, name)
def req_sub(self, widget, jid, txt): def req_sub(self, widget, jid, txt):
"""Request subscription to a user"""
self.queueOUT.put(('SUB', (jid, txt))) self.queueOUT.put(('SUB', (jid, txt)))
if not self.l_contact.has_key(jid): if not self.l_contact.has_key(jid):
user1 = user(jid, jid, ['general'], 'requested', 'requested', 'sub', '') user1 = user(jid, jid, ['general'], 'requested', 'requested', 'sub', '')
self.add_user(user1) self.add_user(user1)
def init_tree(self): def init_tree(self):
"""initialize treeview, l_contact and l_group"""
self.tree.get_model().clear() self.tree.get_model().clear()
#l_contact = {jid:{'user':_, 'iter':[iter1, ...]] #l_contact = {jid:{'user':_, 'iter':[iter1, ...]]
self.l_contact = {} self.l_contact = {}
@ -1007,6 +1051,7 @@ class roster:
self.l_group = {} self.l_group = {}
def on_treeview_event(self, widget, event): def on_treeview_event(self, widget, event):
"""popup user's group's or agent menu"""
if (event.button == 3) & (event.type == gtk.gdk.BUTTON_PRESS): if (event.button == 3) & (event.type == gtk.gdk.BUTTON_PRESS):
try: try:
path, column, x, y = self.tree.get_path_at_pos(int(event.x), int(event.y)) path, column, x, y = self.tree.get_path_at_pos(int(event.x), int(event.y))
@ -1026,9 +1071,11 @@ class roster:
return gtk.FALSE return gtk.FALSE
def on_req_usub(self, widget, iter): def on_req_usub(self, widget, iter):
"""Remove a user"""
window_confirm = confirm(self, iter) window_confirm = confirm(self, iter)
def on_status_changed(self, widget): def on_status_changed(self, widget):
"""When we change our status"""
accountsStr = self.cfgParser.Profile_accounts accountsStr = self.cfgParser.Profile_accounts
accounts = string.split(accountsStr, ' ') accounts = string.split(accountsStr, ' ')
if widget.name != 'online' and widget.name != 'offline': if widget.name != 'online' and widget.name != 'offline':
@ -1039,25 +1086,36 @@ class roster:
self.queueOUT.put(('STATUS',(widget.name, txt, accounts[0]))) self.queueOUT.put(('STATUS',(widget.name, txt, accounts[0])))
def on_prefs(self, widget): def on_prefs(self, widget):
"""When preferences is selected :
call the prefs class"""
window = prefs(self) window = prefs(self)
def on_add(self, widget): def on_add(self, widget):
"""When add user is selected :
call the add class"""
window_add = add(self) window_add = add(self)
def on_about(self, widget): def on_about(self, widget):
"""When about is selected :
call the about class"""
window_about = about() window_about = about()
def on_accounts(self, widget): def on_accounts(self, widget):
"""When accounts is seleted :
call the accounts class to modify accounts"""
global Waccounts global Waccounts
if not Waccounts: if not Waccounts:
Waccounts = accounts(self) Waccounts = accounts(self)
def on_quit(self, widget): def on_quit(self, widget):
"""When we quit the gtk plugin :
tell that to the core and exit gtk"""
self.queueOUT.put(('QUIT','')) self.queueOUT.put(('QUIT',''))
gtk.mainquit() gtk.mainquit()
# sys.exit(0)
def on_row_activated(self, widget, path, col=0): def on_row_activated(self, widget, path, col=0):
"""When an iter is dubble clicked :
open the chat window"""
model = self.tree.get_model() model = self.tree.get_model()
iter = model.get_iter(path) iter = model.get_iter(path)
jid = model.get_value(iter, 2) jid = model.get_value(iter, 2)
@ -1075,12 +1133,19 @@ class roster:
self.tab_messages[jid].read_queue(self.tab_queues[jid]) self.tab_messages[jid].read_queue(self.tab_queues[jid])
def on_row_expanded(self, widget, iter, path): def on_row_expanded(self, widget, iter, path):
"""When a row is expanded :
change the icon of the arrow"""
self.tree.get_model().set_value(iter, 0, self.pixbufs['opened']) self.tree.get_model().set_value(iter, 0, self.pixbufs['opened'])
def on_row_collapsed(self, widget, iter, path): def on_row_collapsed(self, widget, iter, path):
"""When a row is collapsed :
change the icon of the arrow"""
self.tree.get_model().set_value(iter, 0, self.pixbufs['closed']) self.tree.get_model().set_value(iter, 0, self.pixbufs['closed'])
def on_cell_edited (self, cell, row, new_text): def on_cell_edited (self, cell, row, new_text):
"""When an iter is editer :
if text has changed, rename the user
else open chat window"""
model = self.tree.get_model() model = self.tree.get_model()
iter = model.get_iter_from_string(row) iter = model.get_iter_from_string(row)
jid = model.get_value(iter, 2) jid = model.get_value(iter, 2)
@ -1099,22 +1164,33 @@ class roster:
self.queueOUT.put(('UPDUSER', (jid, new_text, self.l_contact[jid]['user'].groups))) self.queueOUT.put(('UPDUSER', (jid, new_text, self.l_contact[jid]['user'].groups)))
def on_browse(self, widget): def on_browse(self, widget):
"""When browse agent is selected :
Call browse class"""
global Wbrowser global Wbrowser
if not Wbrowser: if not Wbrowser:
Wbrowser = browser(self) Wbrowser = browser(self)
def mkpixbufs(self): def mkpixbufs(self):
"""initialise pixbufs array"""
self.path = 'plugins/gtkgui/icons/' + self.iconstyle + '/' self.path = 'plugins/gtkgui/icons/' + self.iconstyle + '/'
self.pixbufs = {} self.pixbufs = {}
for state in ('online', 'away', 'xa', 'dnd', 'offline', 'requested', 'message', 'opened', 'closed'): for state in ('online', 'away', 'xa', 'dnd', 'offline', 'requested', 'message', 'opened', 'closed'):
if not os.path.exists(self.path + state + '.xpm'): #open an animated gif file if it exists oterelse a xpm file
print 'No such file : ' + self.path + state + '.xpm' if not os.path.exists(self.path + state + '.gif'):
self.pixbufs[state] = None if not os.path.exists(self.path + state + '.xpm'):
print 'No such file : ' + self.path + state + '.gif / xpm'
self.pixbufs[state] = None
else:
pix = gtk.gdk.pixbuf_new_from_file(self.path + state + '.xpm')
self.pixbufs[state] = pix
else: else:
pix = gtk.gdk.pixbuf_new_from_file (self.path + state + '.xpm') #TODO: open an animated gif file
pix = gtk.gdk.pixbufAnimation(self.path + state + '.gif')
self.pixbufs[state] = pix self.pixbufs[state] = pix
def on_show_off(self, widget): def on_show_off(self, widget):
"""when show offline option is changed :
redraw the treeview"""
self.showOffline = 1 - self.showOffline self.showOffline = 1 - self.showOffline
self.redraw_roster() self.redraw_roster()
@ -1208,7 +1284,9 @@ class roster:
xml.signal_connect('on_row_collapsed', self.on_row_collapsed) xml.signal_connect('on_row_collapsed', self.on_row_collapsed)
class plugin: class plugin:
"""Class called by the core in a new thread"""
def read_queue(self): def read_queue(self):
"""Read queue from the core and execute commands from it"""
global Wbrowser global Wbrowser
model = self.r.tree.get_model() model = self.r.tree.get_model()
while self.queueIN.empty() == 0: while self.queueIN.empty() == 0:
@ -1217,6 +1295,7 @@ class plugin:
self.r.init_tree() self.r.init_tree()
self.r.mklists(ev[1]) self.r.mklists(ev[1])
self.r.draw_roster() self.r.draw_roster()
#TODO: update onpened chat window
elif ev[0] == 'WARNING': elif ev[0] == 'WARNING':
warning(ev[1]) warning(ev[1])
elif ev[0] == 'STATUS': elif ev[0] == 'STATUS':
@ -1263,9 +1342,7 @@ class plugin:
user1 = user(ji, ji, ['Agents'], ev[1][1], ev[1][2], 'from', res) user1 = user(ji, ji, ['Agents'], ev[1][1], ev[1][2], 'from', res)
self.r.add_user(user1) self.r.add_user(user1)
else: else:
#Update existing line #Update existing iter
# self.l_contact[jid]['user'].show = show
# self.l_contact[jid]['user'].status = status
for i in self.r.l_contact[ji]['iter']: for i in self.r.l_contact[ji]['iter']:
if self.r.pixbufs.has_key(ev[1][1]): if self.r.pixbufs.has_key(ev[1][1]):
model.set_value(i, 0, self.r.pixbufs[ev[1][1]]) model.set_value(i, 0, self.r.pixbufs[ev[1][1]])
@ -1338,7 +1415,8 @@ class plugin:
self.r.on_quit(self) self.r.on_quit(self)
return 1 return 1
def read_sleepy(self): def read_sleepy(self):
"""Check if we are idle"""
if self.sleeper and (self.autoaway or self.autoxa) and \ if self.sleeper and (self.autoaway or self.autoxa) and \
(self.r.optionmenu.get_history()==0 or \ (self.r.optionmenu.get_history()==0 or \
self.sleeper_state!=common.sleepy.STATE_AWAKE): self.sleeper_state!=common.sleepy.STATE_AWAKE):
@ -1348,15 +1426,15 @@ class plugin:
accountsStr = self.r.cfgParser.Profile_accounts accountsStr = self.r.cfgParser.Profile_accounts
accounts = string.split(accountsStr, ' ') accounts = string.split(accountsStr, ' ')
if state == common.sleepy.STATE_AWAKE: if state == common.sleepy.STATE_AWAKE:
#on repasse online #we go online
self.r.optionmenu.set_history(0) self.r.optionmenu.set_history(0)
self.r.queueOUT.put(('STATUS',('online', '', accounts[0]))) self.r.queueOUT.put(('STATUS',('online', '', accounts[0])))
if state == common.sleepy.STATE_AWAY and self.autoaway: if state == common.sleepy.STATE_AWAY and self.autoaway:
#on passe away #we go away
self.r.optionmenu.set_history(1) self.r.optionmenu.set_history(1)
self.r.queueOUT.put(('STATUS',('away', 'auto away (idle)', accounts[0]))) self.r.queueOUT.put(('STATUS',('away', 'auto away (idle)', accounts[0])))
if state == common.sleepy.STATE_XAWAY and self.autoxa: if state == common.sleepy.STATE_XAWAY and self.autoxa:
#on passe away #we go extanded away
self.r.optionmenu.set_history(2) self.r.optionmenu.set_history(2)
self.r.queueOUT.put(('STATUS',('xa', 'auto away (idel)', accounts[0]))) self.r.queueOUT.put(('STATUS',('xa', 'auto away (idel)', accounts[0])))
self.sleeper_state = state self.sleeper_state = state
@ -1388,8 +1466,6 @@ class plugin:
self.sleeper = None self.sleeper = None
self.sleeper_state = None self.sleeper_state = None
gtk.main() gtk.main()
# while 1:
# while gtk.events_pending(): gtk.mainiteration()
gtk.threads_leave() gtk.threads_leave()
if __name__ == "__main__": if __name__ == "__main__":