Scale Avatars for HiDPI Screens
This commit is contained in:
parent
440b6e4829
commit
232dc1dda0
|
@ -1040,9 +1040,11 @@ class ChatControl(ChatControlBase):
|
|||
jid = self.contact.jid
|
||||
|
||||
if app.config.get('show_avatar_in_tabs'):
|
||||
avatar_pixbuf = app.contacts.get_avatar(self.account, jid, size=16)
|
||||
if avatar_pixbuf is not None:
|
||||
return avatar_pixbuf
|
||||
scale = self.parent_win.window.get_scale_factor()
|
||||
surface = app.contacts.get_avatar(
|
||||
self.account, jid, AvatarSize.TAB, scale)
|
||||
if surface is not None:
|
||||
return surface
|
||||
|
||||
if count_unread:
|
||||
num_unread = len(app.events.get_events(self.account, jid,
|
||||
|
@ -1273,18 +1275,19 @@ class ChatControl(ChatControlBase):
|
|||
if not app.config.get('show_avatar_in_chat'):
|
||||
return
|
||||
|
||||
scale = self.parent_win.window.get_scale_factor()
|
||||
if self.TYPE_ID == message_control.TYPE_CHAT:
|
||||
pixbuf = app.contacts.get_avatar(
|
||||
self.account, self.contact.jid, AvatarSize.CHAT)
|
||||
surface = app.contacts.get_avatar(
|
||||
self.account, self.contact.jid, AvatarSize.CHAT, scale)
|
||||
else:
|
||||
pixbuf = app.interface.get_avatar(
|
||||
self.gc_contact.avatar_sha, AvatarSize.CHAT)
|
||||
surface = app.interface.get_avatar(
|
||||
self.gc_contact.avatar_sha, AvatarSize.CHAT, scale)
|
||||
|
||||
image = self.xml.get_object('avatar_image')
|
||||
if pixbuf is None:
|
||||
if surface is None:
|
||||
image.set_from_icon_name('avatar-default', Gtk.IconSize.DIALOG)
|
||||
else:
|
||||
image.set_from_pixbuf(pixbuf)
|
||||
image.set_from_surface(surface)
|
||||
|
||||
def _nec_update_avatar(self, obj):
|
||||
if obj.account != self.account:
|
||||
|
|
|
@ -29,6 +29,7 @@ class OptionType(IntEnum):
|
|||
DIALOG = 4
|
||||
|
||||
class AvatarSize(IntEnum):
|
||||
TAB = 16
|
||||
ROSTER = 32
|
||||
CHAT = 48
|
||||
NOTIFICATION = 48
|
||||
|
|
|
@ -197,8 +197,8 @@ class GC_Contact(CommonContact):
|
|||
def get_shown_name(self):
|
||||
return self.name
|
||||
|
||||
def get_avatar(self, size=None):
|
||||
return common.app.interface.get_avatar(self.avatar_sha, size)
|
||||
def get_avatar(self, *args, **kwargs):
|
||||
return common.app.interface.get_avatar(self.avatar_sha, *args, **kwargs)
|
||||
|
||||
def as_contact(self):
|
||||
"""
|
||||
|
@ -310,8 +310,8 @@ class LegacyContactsAPI:
|
|||
def get_contact(self, account, jid, resource=None):
|
||||
return self._accounts[account].contacts.get_contact(jid, resource=resource)
|
||||
|
||||
def get_avatar(self, account, jid, size=None):
|
||||
return self._accounts[account].contacts.get_avatar(jid, size)
|
||||
def get_avatar(self, account, *args, **kwargs):
|
||||
return self._accounts[account].contacts.get_avatar(*args, **kwargs)
|
||||
|
||||
def get_avatar_sha(self, account, jid):
|
||||
return self._accounts[account].contacts.get_avatar_sha(jid)
|
||||
|
@ -509,14 +509,15 @@ class Contacts():
|
|||
return c
|
||||
return self._contacts[jid][0]
|
||||
|
||||
def get_avatar(self, jid, size=None):
|
||||
def get_avatar(self, jid, size=None, scale=None):
|
||||
if jid not in self._contacts:
|
||||
return None
|
||||
|
||||
for resource in self._contacts[jid]:
|
||||
if resource.avatar_sha is None:
|
||||
continue
|
||||
avatar = common.app.interface.get_avatar(resource.avatar_sha, size)
|
||||
avatar = common.app.interface.get_avatar(
|
||||
resource.avatar_sha, size, scale)
|
||||
if avatar is None:
|
||||
self.set_avatar(jid, None)
|
||||
return avatar
|
||||
|
|
|
@ -77,25 +77,38 @@ class Column(IntEnum):
|
|||
NICK = 1 # contact nickame or ROLE name
|
||||
TYPE = 2 # type of the row ('contact' or 'role')
|
||||
TEXT = 3 # text shown in the cellrenderer
|
||||
AVATAR = 4 # avatar of the contact
|
||||
AVATAR_IMG = 4 # avatar of the contact
|
||||
|
||||
empty_pixbuf = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, True, 8, 1, 1)
|
||||
empty_pixbuf.fill(0xffffff00)
|
||||
|
||||
def tree_cell_data_func(column, renderer, model, iter_, tv=None):
|
||||
|
||||
def status_cell_data_func(column, renderer, model, iter_, user_data):
|
||||
renderer.set_property('width', 26)
|
||||
image = model[iter_][Column.IMG]
|
||||
surface = image.get_property('surface')
|
||||
renderer.set_property('surface', surface)
|
||||
|
||||
|
||||
def tree_cell_data_func(column, renderer, model, iter_, user_data):
|
||||
# cell data func is global, because we don't want it to keep
|
||||
# reference to GroupchatControl instance (self)
|
||||
theme = app.config.get('roster_theme')
|
||||
# allocate space for avatar only if needed
|
||||
parent_iter = model.iter_parent(iter_)
|
||||
if isinstance(renderer, Gtk.CellRendererPixbuf):
|
||||
image = model[iter_][Column.AVATAR_IMG]
|
||||
if image is None:
|
||||
return
|
||||
surface = image.get_property('surface')
|
||||
renderer.set_property('surface', surface)
|
||||
|
||||
avatar_position = app.config.get('avatar_position_in_roster')
|
||||
if avatar_position == 'right':
|
||||
renderer.set_property('xalign', 1) # align pixbuf to the right
|
||||
else:
|
||||
renderer.set_property('xalign', 0.5)
|
||||
if parent_iter and (model[iter_][Column.AVATAR] or avatar_position == \
|
||||
'left'):
|
||||
if parent_iter:
|
||||
renderer.set_property('visible', True)
|
||||
renderer.set_property('width', AvatarSize.ROSTER)
|
||||
else:
|
||||
|
@ -254,6 +267,16 @@ class PrivateChatControl(ChatControl):
|
|||
return
|
||||
self.show_avatar()
|
||||
|
||||
def show_avatar(self):
|
||||
if not app.config.get('show_avatar_in_chat'):
|
||||
return
|
||||
|
||||
scale = self.parent_win.window.get_scale_factor()
|
||||
surface = app.interface.get_avatar(
|
||||
self.gc_contact.avatar_sha, AvatarSize.CHAT, scale)
|
||||
image = self.xml.get_object('avatar_image')
|
||||
image.set_from_surface(surface)
|
||||
|
||||
def update_contact(self):
|
||||
self.contact = self.gc_contact.as_contact()
|
||||
|
||||
|
@ -308,6 +331,9 @@ class GroupchatControl(ChatControlBase):
|
|||
# Tooltip Window and Actions have to be created with parent
|
||||
self.set_tooltip()
|
||||
self.add_actions()
|
||||
self.scale_factor = parent_win.window.get_scale_factor()
|
||||
else:
|
||||
self.scale_factor = app.interface.roster.scale_factor
|
||||
|
||||
widget = self.xml.get_object('list_treeview')
|
||||
id_ = widget.connect('row_expanded', self.on_list_treeview_row_expanded)
|
||||
|
@ -392,7 +418,7 @@ class GroupchatControl(ChatControlBase):
|
|||
self.hpaned.set_position(hpaned_position)
|
||||
|
||||
#status_image, shown_nick, type, nickname, avatar
|
||||
self.columns = [Gtk.Image, str, str, str, GdkPixbuf.Pixbuf]
|
||||
self.columns = [Gtk.Image, str, str, str, Gtk.Image]
|
||||
self.model = Gtk.TreeStore(*self.columns)
|
||||
self.model.set_sort_func(Column.NICK, self.tree_compare_iters)
|
||||
self.model.set_sort_column_id(Column.NICK, Gtk.SortType.ASCENDING)
|
||||
|
@ -415,20 +441,20 @@ class GroupchatControl(ChatControlBase):
|
|||
self.renderers_list += (
|
||||
# status img
|
||||
('icon', renderer_image, False,
|
||||
'image', Column.IMG, tree_cell_data_func, self.list_treeview),
|
||||
'image', Column.IMG, tree_cell_data_func, None),
|
||||
# contact name
|
||||
('name', renderer_text, True,
|
||||
'markup', Column.TEXT, tree_cell_data_func, self.list_treeview))
|
||||
'markup', Column.TEXT, tree_cell_data_func, None))
|
||||
|
||||
# avatar img
|
||||
avater_renderer = ('avatar', Gtk.CellRendererPixbuf(),
|
||||
False, 'pixbuf', Column.AVATAR,
|
||||
tree_cell_data_func, self.list_treeview)
|
||||
avatar_renderer = ('avatar', Gtk.CellRendererPixbuf(),
|
||||
False, None, Column.AVATAR_IMG,
|
||||
tree_cell_data_func, None)
|
||||
|
||||
if app.config.get('avatar_position_in_roster') == 'right':
|
||||
self.renderers_list.append(avater_renderer)
|
||||
self.renderers_list.append(avatar_renderer)
|
||||
else:
|
||||
self.renderers_list.insert(0, avater_renderer)
|
||||
self.renderers_list.insert(0, avatar_renderer)
|
||||
|
||||
self.fill_column(column)
|
||||
self.list_treeview.append_column(column)
|
||||
|
@ -782,7 +808,8 @@ class GroupchatControl(ChatControlBase):
|
|||
def fill_column(self, col):
|
||||
for rend in self.renderers_list:
|
||||
col.pack_start(rend[1], rend[2])
|
||||
col.add_attribute(rend[1], rend[3], rend[4])
|
||||
if rend[0] != 'avatar':
|
||||
col.add_attribute(rend[1], rend[3], rend[4])
|
||||
col.set_cell_data_func(rend[1], rend[5], rend[6])
|
||||
# set renderers propertys
|
||||
for renderer in self.renderers_propertys.keys():
|
||||
|
@ -1652,8 +1679,10 @@ class GroupchatControl(ChatControlBase):
|
|||
if not iter_:
|
||||
return
|
||||
|
||||
pixbuf = app.interface.get_avatar(gc_contact.avatar_sha, AvatarSize.ROSTER)
|
||||
self.model[iter_][Column.AVATAR] = pixbuf or empty_pixbuf
|
||||
surface = app.interface.get_avatar(
|
||||
gc_contact.avatar_sha, AvatarSize.ROSTER, self.scale_factor)
|
||||
image = Gtk.Image.new_from_surface(surface)
|
||||
self.model[iter_][Column.AVATAR_IMG] = image
|
||||
|
||||
def draw_role(self, role):
|
||||
role_iter = self.get_role_iter(role)
|
||||
|
|
|
@ -44,6 +44,7 @@ from gi.repository import Gtk
|
|||
from gi.repository import GdkPixbuf
|
||||
from gi.repository import GLib
|
||||
from gi.repository import Gio
|
||||
from gi.repository import Gdk
|
||||
|
||||
try:
|
||||
from PIL import Image
|
||||
|
@ -2449,10 +2450,16 @@ class Interface:
|
|||
return sha
|
||||
|
||||
@staticmethod
|
||||
def get_avatar(filename, size=None, publish=False):
|
||||
def get_avatar(filename, size=None, scale=None, publish=False):
|
||||
if filename is None or '':
|
||||
return
|
||||
|
||||
if size is None and scale is not None:
|
||||
raise ValueError
|
||||
|
||||
if scale is not None:
|
||||
size = size * scale
|
||||
|
||||
if publish:
|
||||
path = os.path.join(app.AVATAR_PATH, filename)
|
||||
with open(path, 'rb') as file:
|
||||
|
@ -2460,8 +2467,10 @@ class Interface:
|
|||
return data
|
||||
|
||||
try:
|
||||
sha = app.avatar_cache[filename][size]
|
||||
return sha
|
||||
pixbuf = app.avatar_cache[filename][size]
|
||||
if scale is None:
|
||||
return pixbuf
|
||||
return Gdk.cairo_surface_create_from_pixbuf(pixbuf, scale)
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
|
@ -2501,7 +2510,9 @@ class Interface:
|
|||
app.avatar_cache[filename] = {}
|
||||
app.avatar_cache[filename][size] = pixbuf
|
||||
|
||||
return pixbuf
|
||||
if scale is None:
|
||||
return pixbuf
|
||||
return Gdk.cairo_surface_create_from_pixbuf(pixbuf, scale)
|
||||
|
||||
def auto_join_bookmarks(self, account):
|
||||
"""
|
||||
|
|
|
@ -680,12 +680,13 @@ class MessageWindow(object):
|
|||
|
||||
tab_img = ctrl.get_tab_image()
|
||||
if tab_img:
|
||||
if isinstance(tab_img, GdkPixbuf.Pixbuf):
|
||||
status_img.set_from_pixbuf(tab_img)
|
||||
elif tab_img.get_storage_type() == Gtk.ImageType.ANIMATION:
|
||||
status_img.set_from_animation(tab_img.get_animation())
|
||||
if isinstance(tab_img, Gtk.Image):
|
||||
if tab_img.get_storage_type() == Gtk.ImageType.ANIMATION:
|
||||
status_img.set_from_animation(tab_img.get_animation())
|
||||
else:
|
||||
status_img.set_from_pixbuf(tab_img.get_pixbuf())
|
||||
else:
|
||||
status_img.set_from_pixbuf(tab_img.get_pixbuf())
|
||||
status_img.set_from_surface(tab_img)
|
||||
|
||||
self.show_icon()
|
||||
|
||||
|
|
|
@ -131,11 +131,12 @@ class ProfileWindow:
|
|||
self.dialog.destroy()
|
||||
self.dialog = None
|
||||
|
||||
pixbuf = app.interface.get_avatar(sha, AvatarSize.VCARD)
|
||||
scale = self.window.get_scale_factor()
|
||||
surface = app.interface.get_avatar(sha, AvatarSize.VCARD, scale)
|
||||
|
||||
button = self.xml.get_object('PHOTO_button')
|
||||
image = button.get_image()
|
||||
image.set_from_pixbuf(pixbuf)
|
||||
image.set_from_surface(surface)
|
||||
button.show()
|
||||
text_button = self.xml.get_object('NOPHOTO_button')
|
||||
text_button.hide()
|
||||
|
|
|
@ -82,7 +82,7 @@ class Column(IntEnum):
|
|||
ACTIVITY_PIXBUF = 6
|
||||
TUNE_PIXBUF = 7
|
||||
LOCATION_PIXBUF = 8
|
||||
AVATAR_PIXBUF = 9 # avatar_pixbuf
|
||||
AVATAR_IMG = 9 # avatar_sha
|
||||
PADLOCK_PIXBUF = 10 # use for account row only
|
||||
VISIBLE = 11
|
||||
|
||||
|
@ -1397,11 +1397,12 @@ class RosterWindow:
|
|||
return
|
||||
jid = self.model[iters[0]][Column.JID]
|
||||
|
||||
pixbuf = app.contacts.get_avatar(account, jid, size=AvatarSize.ROSTER)
|
||||
if pixbuf is None:
|
||||
pixbuf = empty_pixbuf
|
||||
scale = self.window.get_scale_factor()
|
||||
surface = app.contacts.get_avatar(
|
||||
account, jid, AvatarSize.ROSTER, scale)
|
||||
image = Gtk.Image.new_from_surface(surface)
|
||||
for child_iter in iters:
|
||||
self.model[child_iter][Column.AVATAR_PIXBUF] = pixbuf
|
||||
self.model[child_iter][Column.AVATAR_IMG] = image
|
||||
return False
|
||||
|
||||
def draw_completely(self, jid, account):
|
||||
|
@ -2251,7 +2252,7 @@ class RosterWindow:
|
|||
else:
|
||||
# No need to redraw contacts if we're quitting
|
||||
if child_iterA:
|
||||
self.model[child_iterA][Column.AVATAR_PIXBUF] = empty_pixbuf
|
||||
self.model[child_iterA][Column.AVATAR_IMG] = None
|
||||
if account in app.con_types:
|
||||
app.con_types[account] = None
|
||||
for jid in list(app.contacts.get_jid_list(account)):
|
||||
|
@ -4836,8 +4837,11 @@ class RosterWindow:
|
|||
renderer.set_property('visible', False)
|
||||
return
|
||||
|
||||
image = model[titer][Column.AVATAR_IMG]
|
||||
surface = image.get_property('surface')
|
||||
renderer.set_property('surface', surface)
|
||||
# allocate space for the icon only if needed
|
||||
if model[titer][Column.AVATAR_PIXBUF] or \
|
||||
if model[titer][Column.AVATAR_IMG] or \
|
||||
app.config.get('avatar_position_in_roster') == 'left':
|
||||
renderer.set_property('visible', True)
|
||||
if type_:
|
||||
|
@ -4850,7 +4854,7 @@ class RosterWindow:
|
|||
self._set_contact_row_background_color(renderer, jid, account)
|
||||
else:
|
||||
renderer.set_property('visible', False)
|
||||
if model[titer][Column.AVATAR_PIXBUF] == empty_pixbuf and \
|
||||
if model[titer][Column.AVATAR_IMG] is None and \
|
||||
app.config.get('avatar_position_in_roster') != 'left':
|
||||
renderer.set_property('visible', False)
|
||||
|
||||
|
@ -5561,7 +5565,8 @@ class RosterWindow:
|
|||
def fill_column(self, col):
|
||||
for rend in self.renderers_list:
|
||||
col.pack_start(rend[1], rend[2])
|
||||
col.add_attribute(rend[1], rend[3], rend[4])
|
||||
if rend[0] != 'avatar':
|
||||
col.add_attribute(rend[1], rend[3], rend[4])
|
||||
col.set_cell_data_func(rend[1], rend[5], rend[6])
|
||||
# set renderers propertys
|
||||
for renderer in self.renderers_propertys.keys():
|
||||
|
@ -5659,12 +5664,14 @@ class RosterWindow:
|
|||
self.nb_ext_renderers = 0
|
||||
# When we quit, rememver if we already saved config once
|
||||
self.save_done = False
|
||||
# [icon, name, type, jid, account, mood_pixbuf,
|
||||
# activity_pixbuf, tune_pixbuf, location_pixbuf, avatar_pixbuf,
|
||||
|
||||
# [icon, name, type, jid, account, editable, mood_pixbuf,
|
||||
# activity_pixbuf, tune_pixbuf, location_pixbuf, avatar_img,
|
||||
# padlock_pixbuf, visible]
|
||||
self.columns = [Gtk.Image, str, str, str, str,
|
||||
GdkPixbuf.Pixbuf, GdkPixbuf.Pixbuf, GdkPixbuf.Pixbuf, GdkPixbuf.Pixbuf,
|
||||
GdkPixbuf.Pixbuf, GdkPixbuf.Pixbuf, bool]
|
||||
Gtk.Image, str, bool]
|
||||
|
||||
self.xml = gtkgui_helpers.get_gtk_builder('roster_window.ui')
|
||||
self.window = self.xml.get_object('roster_window')
|
||||
application.add_window(self.window)
|
||||
|
@ -5819,7 +5826,7 @@ class RosterWindow:
|
|||
|
||||
def add_avatar_renderer():
|
||||
self.renderers_list.append(('avatar', Gtk.CellRendererPixbuf(),
|
||||
False, 'pixbuf', Column.AVATAR_PIXBUF,
|
||||
False, None, Column.AVATAR_IMG,
|
||||
self._fill_avatar_pixbuf_renderer, None))
|
||||
|
||||
if app.config.get('avatar_position_in_roster') == 'left':
|
||||
|
@ -5908,6 +5915,8 @@ class RosterWindow:
|
|||
app.config.get('trayicon') != 'always':
|
||||
self.window.show_all()
|
||||
|
||||
self.scale_factor = self.window.get_scale_factor()
|
||||
|
||||
if not app.config.get_per('accounts') or \
|
||||
app.config.get_per('accounts') == ['Local'] and not \
|
||||
app.config.get_per('accounts', 'Local', 'active'):
|
||||
|
|
|
@ -244,9 +244,11 @@ class GCTooltip():
|
|||
if contact.avatar_sha is not None:
|
||||
app.log('avatar').debug(
|
||||
'Load GCTooltip: %s %s', contact.name, contact.avatar_sha)
|
||||
pixbuf = app.interface.get_avatar(contact.avatar_sha, AvatarSize.TOOLTIP)
|
||||
if pixbuf is not None:
|
||||
self.avatar.set_from_pixbuf(pixbuf)
|
||||
scale = self.tooltip_grid.get_scale_factor()
|
||||
surface = app.interface.get_avatar(
|
||||
contact.avatar_sha, AvatarSize.TOOLTIP, scale)
|
||||
if surface is not None:
|
||||
self.avatar.set_from_surface(surface)
|
||||
self.avatar.show()
|
||||
self.fillelement.show()
|
||||
|
||||
|
@ -521,11 +523,12 @@ class RosterTooltip(Gtk.Window, StatusTable):
|
|||
self._set_idle_time(contact)
|
||||
|
||||
# Avatar
|
||||
pixbuf = app.contacts.get_avatar(
|
||||
account, self.prim_contact.jid, AvatarSize.TOOLTIP)
|
||||
if pixbuf is None:
|
||||
scale = self.get_scale_factor()
|
||||
surface = app.contacts.get_avatar(
|
||||
account, self.prim_contact.jid, AvatarSize.TOOLTIP, scale)
|
||||
if surface is None:
|
||||
return
|
||||
self.avatar.set_from_pixbuf(pixbuf)
|
||||
self.avatar.set_from_surface(surface)
|
||||
self.avatar.show()
|
||||
|
||||
# Sets the Widget that is at the bottom to expand.
|
||||
|
|
Loading…
Reference in New Issue