|
|
@ -99,7 +99,7 @@ class _WorkerThread(threading.Thread, _IdleObject): |
|
|
|
|
|
|
|
|
|
|
|
def run(self): |
|
|
|
def run(self): |
|
|
|
# call the function |
|
|
|
# call the function |
|
|
|
_log.debug('Thread %s calling %s', self.ident, str(self._function)) |
|
|
|
_log.debug('Thread %s calling %s', self.name, str(self._function)) |
|
|
|
|
|
|
|
|
|
|
|
args = self._args |
|
|
|
args = self._args |
|
|
|
kwargs = self._kwargs |
|
|
|
kwargs = self._kwargs |
|
|
@ -183,6 +183,76 @@ class _ThreadManager(object): |
|
|
|
self._thread_id += 1 |
|
|
|
self._thread_id += 1 |
|
|
|
return |
|
|
|
return |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
|
|
|
|
|
|
|
# Custom cell renderer |
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
|
|
|
|
|
|
|
class CellRendererNetworkData(gtk.GenericCellrenderer): |
|
|
|
|
|
|
|
"""A customized cell renderer for messages.""" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
__gproperties__ = { |
|
|
|
|
|
|
|
'message': (gobject.TYPE_PYOBJECT, |
|
|
|
|
|
|
|
'message', |
|
|
|
|
|
|
|
'A NetworkData object to be rendered', |
|
|
|
|
|
|
|
'', |
|
|
|
|
|
|
|
gobject.PARAM_WRITABLE) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def __init__(self): |
|
|
|
|
|
|
|
super(CellrendererNetworkData, self).__init__(self) |
|
|
|
|
|
|
|
self.set_property('mode', gtk.CELL_RENDERER_MODE_ACTIVATABLE) |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def on_render(self, window, widget, bg_area, cell_area, exp_area, flags): |
|
|
|
|
|
|
|
"""The render() method invokes the virtual render function of the |
|
|
|
|
|
|
|
gtk.CellRenderer. The three passed-in rectangles are areas of window. |
|
|
|
|
|
|
|
Most renderers will draw within cell_area; the xalign, yalign, xpad, |
|
|
|
|
|
|
|
and ypad properties of the gtk.CellRenderer should be honored with |
|
|
|
|
|
|
|
respect to cell_area. background_area includes the blank space around |
|
|
|
|
|
|
|
the cell, and also the area containing the tree expander; so the |
|
|
|
|
|
|
|
background_area rectangles for all cells tile to cover the entire |
|
|
|
|
|
|
|
window. expose_area is a clip rectangle. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The flags value is one of: gtk.CELL_RENDERER_SELECTED, |
|
|
|
|
|
|
|
gtk.CELL_RENDERER_PRELIT, gtk.CELL_RENDERER_INSENSITIVE or |
|
|
|
|
|
|
|
gtk.CELL_RENDERER_SORTED""" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
layout = self.get_layout(widget) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if flags & gtk.CELL_RENDERER_SELECTED: |
|
|
|
|
|
|
|
if widget.get_property('has-focus'): |
|
|
|
|
|
|
|
state = gtk.STATE_SELECTED |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
satte = gtk.STATE_ACTIVE |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
state = gtk.STATE_NORMAL |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
widget.style.paint_layout( |
|
|
|
|
|
|
|
window, |
|
|
|
|
|
|
|
state, |
|
|
|
|
|
|
|
True, |
|
|
|
|
|
|
|
cell_area, |
|
|
|
|
|
|
|
widget, |
|
|
|
|
|
|
|
'foo', |
|
|
|
|
|
|
|
cell_area.x + x_offset, |
|
|
|
|
|
|
|
cell_area.y + y_offset, |
|
|
|
|
|
|
|
layout |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def on_get_size(sel, widget, cell_area): |
|
|
|
|
|
|
|
"""The get_size() method obtains the width and height needed to render |
|
|
|
|
|
|
|
the cell. These values are returned as part of a tuple containing the |
|
|
|
|
|
|
|
x_offset, y_offset, width and height. get_size() is used by view |
|
|
|
|
|
|
|
widgets to determine the appropriate size for the cell_area to be |
|
|
|
|
|
|
|
passed to the gtk.CellRenderer.render() method. If cell_area is not |
|
|
|
|
|
|
|
None, the x and y offsets of the cell relative to this location are |
|
|
|
|
|
|
|
returned. Please note that the values set in the returned width and |
|
|
|
|
|
|
|
height, as well as those in x_offset and y_offset are inclusive of the |
|
|
|
|
|
|
|
xpad and ypad properties.""" |
|
|
|
|
|
|
|
return (x_offset, y_offset, width, height) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gobject.type_register(CellRendererNetworkData) |
|
|
|
|
|
|
|
|
|
|
|
# ---------------------------------------------------------------------- |
|
|
|
# ---------------------------------------------------------------------- |
|
|
|
# Mitter interface object |
|
|
|
# Mitter interface object |
|
|
|
# ---------------------------------------------------------------------- |
|
|
|
# ---------------------------------------------------------------------- |
|
|
@ -230,7 +300,7 @@ class Interface(object): |
|
|
|
|
|
|
|
|
|
|
|
main_window.connect('destroy', self._quit_app) |
|
|
|
main_window.connect('destroy', self._quit_app) |
|
|
|
main_window.connect('delete-event', self._quit_app) |
|
|
|
main_window.connect('delete-event', self._quit_app) |
|
|
|
main_window.connect('size-request', self._window_resize) |
|
|
|
main_window.connect('size-request', self._grid_resize) |
|
|
|
|
|
|
|
|
|
|
|
grid = self._create_grid() |
|
|
|
grid = self._create_grid() |
|
|
|
(menu, toolbar, accelerators) = self._create_menu_and_toolbar() |
|
|
|
(menu, toolbar, accelerators) = self._create_menu_and_toolbar() |
|
|
@ -263,19 +333,31 @@ class Interface(object): |
|
|
|
|
|
|
|
|
|
|
|
user_renderer = gtk.CellRendererPixbuf() |
|
|
|
user_renderer = gtk.CellRendererPixbuf() |
|
|
|
user_column = gtk.TreeViewColumn('User', user_renderer) |
|
|
|
user_column = gtk.TreeViewColumn('User', user_renderer) |
|
|
|
|
|
|
|
user_column.set_fixed_width(48) # avatar size (we resize to 48x48) |
|
|
|
|
|
|
|
user_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) |
|
|
|
user_column.set_cell_data_func(user_renderer, |
|
|
|
user_column.set_cell_data_func(user_renderer, |
|
|
|
self._cell_renderer_user) |
|
|
|
self._cell_renderer_user) |
|
|
|
self._grid.append_column(user_column) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
message_renderer = gtk.CellRendererText() |
|
|
|
message_renderer = gtk.CellRendererText() |
|
|
|
message_renderer.set_property('wrap-mode', gtk.WRAP_WORD) |
|
|
|
message_renderer.set_property('wrap-mode', gtk.WRAP_WORD) |
|
|
|
message_renderer.set_property('wrap-width', 200) |
|
|
|
message_renderer.set_property('wrap-width', 200) |
|
|
|
message_renderer.set_property('width', 10) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
message_column = gtk.TreeViewColumn('Message', |
|
|
|
message_column = gtk.TreeViewColumn('Message', |
|
|
|
message_renderer) |
|
|
|
message_renderer) |
|
|
|
message_column.set_cell_data_func(message_renderer, |
|
|
|
message_column.set_cell_data_func(message_renderer, |
|
|
|
self._cell_renderer_message) |
|
|
|
self._cell_renderer_message) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
options_renderer = gtk.CellRendererPixbuf() |
|
|
|
|
|
|
|
options_renderer.set_fixed_size(16, 16) |
|
|
|
|
|
|
|
options_column = gtk.TreeViewColumn('Options', options_renderer) |
|
|
|
|
|
|
|
options_column.set_cell_data_func(options_renderer, |
|
|
|
|
|
|
|
self._cell_renderer_options) |
|
|
|
|
|
|
|
#options_column.set_fixed_width(16) # icon size |
|
|
|
|
|
|
|
#options_column.set_max_width(16) |
|
|
|
|
|
|
|
#options_column.set_expand(False) |
|
|
|
|
|
|
|
#options_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
self._grid.append_column(user_column) |
|
|
|
|
|
|
|
self._grid.append_column(options_column) |
|
|
|
self._grid.append_column(message_column) |
|
|
|
self._grid.append_column(message_column) |
|
|
|
|
|
|
|
|
|
|
|
self._grid.set_resize_mode(gtk.RESIZE_IMMEDIATE) |
|
|
|
self._grid.set_resize_mode(gtk.RESIZE_IMMEDIATE) |
|
|
@ -498,14 +580,13 @@ class Interface(object): |
|
|
|
|
|
|
|
|
|
|
|
# unescape escaped entities that pango is not okay with |
|
|
|
# unescape escaped entities that pango is not okay with |
|
|
|
message = re.sub(r'&', r'&', message) |
|
|
|
message = re.sub(r'&', r'&', message) |
|
|
|
#_log.debug('Rendering message: %s', message) |
|
|
|
_log.debug('Rendering message: %s', message) |
|
|
|
|
|
|
|
|
|
|
|
# highlight URLs |
|
|
|
# highlight URLs |
|
|
|
mask = r'<span foreground="%s">\1</span>' % ( |
|
|
|
mask = r'<span foreground="%s">\1</span>' % ( |
|
|
|
self._options[self.NAMESPACE]['link_colour']) |
|
|
|
self._options[self.NAMESPACE]['link_colour']) |
|
|
|
message = URL_RE.sub(mask, message) |
|
|
|
message = URL_RE.sub(mask, message) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# use a different highlight for the current user |
|
|
|
# use a different highlight for the current user |
|
|
|
#message = re.sub(r'(@'+self.twitter.username+')', |
|
|
|
#message = re.sub(r'(@'+self.twitter.username+')', |
|
|
|
# r'<span foreground="#FF6633">\1</span>', |
|
|
|
# r'<span foreground="#FF6633">\1</span>', |
|
|
@ -517,6 +598,13 @@ class Interface(object): |
|
|
|
|
|
|
|
|
|
|
|
return |
|
|
|
return |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _cell_renderer_options(self, column, cell, store, position): |
|
|
|
|
|
|
|
"""Callback for the options renderer. Adds the delete icon if the |
|
|
|
|
|
|
|
message belongs to the user or reply if not.""" |
|
|
|
|
|
|
|
data = store.get_value(position, 0) |
|
|
|
|
|
|
|
cell.set_property('pixbuf', self._reply_pixbuf) |
|
|
|
|
|
|
|
return |
|
|
|
|
|
|
|
|
|
|
|
# ------------------------------------------------------------ |
|
|
|
# ------------------------------------------------------------ |
|
|
|
# Helper functions |
|
|
|
# Helper functions |
|
|
|
# ------------------------------------------------------------ |
|
|
|
# ------------------------------------------------------------ |
|
|
@ -577,26 +665,34 @@ class Interface(object): |
|
|
|
gtk.main_quit() |
|
|
|
gtk.main_quit() |
|
|
|
return |
|
|
|
return |
|
|
|
|
|
|
|
|
|
|
|
def _window_resize(self, widget, request, data=None): |
|
|
|
def _grid_resize(self, widget, allocation, data=None): |
|
|
|
"""Called when the window is resized. We use it to set the proper |
|
|
|
"""Called when the window is resized. We use it to set the proper |
|
|
|
word-wrapping in the message column.""" |
|
|
|
word-wrapping in the message column.""" |
|
|
|
|
|
|
|
|
|
|
|
(width, height) = widget.get_size() |
|
|
|
|
|
|
|
model = self._grid.get_model() |
|
|
|
model = self._grid.get_model() |
|
|
|
|
|
|
|
|
|
|
|
if len(model) == 0: |
|
|
|
if len(model) == 0: |
|
|
|
# nothing in the list, so we don't have what to set proper word |
|
|
|
# nothing in the list, so we don't have what to set proper word |
|
|
|
# wrapping |
|
|
|
# wrapping |
|
|
|
return |
|
|
|
return |
|
|
|
|
|
|
|
|
|
|
|
column = self._grid.get_column(1) |
|
|
|
_log.debug('Widget size: %d', allocation.width) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
column = self._grid.get_column(2) |
|
|
|
iter = model.get_iter_first() |
|
|
|
iter = model.get_iter_first() |
|
|
|
path = model.get_path(iter) |
|
|
|
path = model.get_path(iter) |
|
|
|
|
|
|
|
|
|
|
|
column_rectangle = self._grid.get_cell_area(path, column) |
|
|
|
cell_rectangle = self._grid.get_cell_area(path, column) |
|
|
|
|
|
|
|
# x_padding |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# focus-line-width |
|
|
|
|
|
|
|
focus_line_width = self._grid.style_get_property('focus-line-width') |
|
|
|
|
|
|
|
#rectangle_width = column_rectangle.width |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
width = cell_rectangle.width - focus_line_width |
|
|
|
|
|
|
|
|
|
|
|
for renderer in column.get_cell_renderers(): |
|
|
|
for renderer in column.get_cell_renderers(): |
|
|
|
renderer.set_property('wrap-width', column_rectangle.width) |
|
|
|
renderer.set_property('wrap-width', width) |
|
|
|
|
|
|
|
renderer.set_property('width', width) |
|
|
|
|
|
|
|
|
|
|
|
while iter: |
|
|
|
while iter: |
|
|
|
path = model.get_path(iter) |
|
|
|
path = model.get_path(iter) |
|
|
@ -711,6 +807,9 @@ class Interface(object): |
|
|
|
# Load images |
|
|
|
# Load images |
|
|
|
self._app_icon = find_image('mitter.png') |
|
|
|
self._app_icon = find_image('mitter.png') |
|
|
|
self._app_icon_alert = find_image('mitter-new.png') |
|
|
|
self._app_icon_alert = find_image('mitter-new.png') |
|
|
|
|
|
|
|
self._reply_pixbuf = gtk.gdk.pixbuf_new_from_file( |
|
|
|
|
|
|
|
find_image('reply.png')) |
|
|
|
|
|
|
|
#self._delete_icon = find_image('icon_trash.gif') |
|
|
|
|
|
|
|
|
|
|
|
unknown_pixbuf = find_image('unknown.png') |
|
|
|
unknown_pixbuf = find_image('unknown.png') |
|
|
|
if unknown_pixbuf: |
|
|
|
if unknown_pixbuf: |
|
|
|