aboutsummaryrefslogtreecommitdiff
path: root/main/src/ui/avatar_image.vala
diff options
context:
space:
mode:
Diffstat (limited to 'main/src/ui/avatar_image.vala')
-rw-r--r--main/src/ui/avatar_image.vala325
1 files changed, 76 insertions, 249 deletions
diff --git a/main/src/ui/avatar_image.vala b/main/src/ui/avatar_image.vala
index cc700f00..a3b386e3 100644
--- a/main/src/ui/avatar_image.vala
+++ b/main/src/ui/avatar_image.vala
@@ -9,16 +9,15 @@ public class AvatarImage : Misc {
public int height { get; set; default = 35; }
public int width { get; set; default = 35; }
public bool allow_gray { get; set; default = true; }
- public Account account { get; private set; }
- public StreamInteractor stream_interactor { get; set; }
- public AvatarManager avatar_manager { owned get { return stream_interactor.get_module(AvatarManager.IDENTITY); } }
- public MucManager muc_manager { owned get { return stream_interactor.get_module(MucManager.IDENTITY); } }
- private Jid jid;
- private string? text_only;
- private bool with_plus;
- private bool gray;
- private Jid[] current_jids;
- private Gdk.Pixbuf[] current_avatars;
+ public StreamInteractor? stream_interactor { get; set; }
+ public AvatarManager? avatar_manager { owned get { return stream_interactor == null ? null : stream_interactor.get_module(AvatarManager.IDENTITY); } }
+ public MucManager? muc_manager { owned get { return stream_interactor == null ? null : stream_interactor.get_module(MucManager.IDENTITY); } }
+ public PresenceManager? presence_manager { owned get { return stream_interactor == null ? null : stream_interactor.get_module(PresenceManager.IDENTITY); } }
+ public ConnectionManager? connection_manager { owned get { return stream_interactor == null ? null : stream_interactor.connection_manager; } }
+ public Account account { get { return conversation.account; } }
+ private AvatarDrawer? drawer;
+ private Conversation conversation;
+ private Jid[] jids;
private Cairo.ImageSurface? cached_surface;
private static int8 use_image_surface = -1;
@@ -37,52 +36,8 @@ public class AvatarImage : Misc {
natural_height = height;
}
- private Cairo.Surface sub_surface(Cairo.Context ctx, int idx, int width, int height, int font_factor = 1) {
- Cairo.Surface buffer = new Cairo.Surface.similar(ctx.get_target(), Cairo.Content.COLOR_ALPHA, width, height);
- Cairo.Context bufctx = new Cairo.Context(buffer);
- if (idx == -1 || current_avatars[idx] == null) {
- set_source_hex_color(bufctx, gray || idx == -1 || current_jids[idx] == null ? "555753" : Util.get_avatar_hex_color(stream_interactor, account, current_jids[idx]));
- bufctx.rectangle(0, 0, width, height);
- bufctx.fill();
-
- string text = text_only ?? (idx == -1 || current_jids[idx] == null ? "…" : Util.get_display_name(stream_interactor, current_jids[idx], account).get_char(0).toupper().to_string());
- bufctx.select_font_face(get_pango_context().get_font_description().get_family(), Cairo.FontSlant.NORMAL, Cairo.FontWeight.NORMAL);
- bufctx.set_font_size(width / font_factor < 40 ? font_factor * 17 : font_factor * 25);
- Cairo.TextExtents extents;
- bufctx.text_extents(text, out extents);
- double x_pos = width/2 - (extents.width/2 + extents.x_bearing);
- double y_pos = height/2 - (extents.height/2 + extents.y_bearing);
- bufctx.move_to(x_pos, y_pos);
- bufctx.set_source_rgba(1, 1, 1, 1);
- bufctx.show_text(text);
- } else {
- double w_scale = (double) width / current_avatars[idx].width;
- double h_scale = (double) height / current_avatars[idx].height;
- double scale = double.max(w_scale, h_scale);
- bufctx.scale(scale, scale);
-
- double x_off = 0, y_off = 0;
- if (scale == h_scale) {
- x_off = (width / scale - current_avatars[idx].width) / 2.0;
- } else {
- y_off = (height / scale - current_avatars[idx].height) / 2.0;
- }
- Gdk.cairo_set_source_pixbuf(bufctx, current_avatars[idx], x_off, y_off);
- bufctx.get_source().set_filter(Cairo.Filter.BEST);
- bufctx.paint();
- }
- return buffer;
- }
-
- private static void set_source_hex_color(Cairo.Context ctx, string hex_color) {
- ctx.set_source_rgba((double) from_hex(hex_color.substring(0, 2)) / 255,
- (double) from_hex(hex_color.substring(2, 2)) / 255,
- (double) from_hex(hex_color.substring(4, 2)) / 255,
- hex_color.length > 6 ? (double) from_hex(hex_color.substring(6, 2)) / 255 : 1);
- }
-
public override bool draw(Cairo.Context ctx_in) {
- if (text_only == null && (current_jids == null || current_avatars == null || current_jids.length == 0)) return false;
+ if (drawer == null) return false;
Cairo.Context ctx = ctx_in;
int width = this.width, height = this.height, base_factor = 1;
@@ -104,82 +59,10 @@ public class AvatarImage : Misc {
ctx = new Cairo.Context(cached_surface);
}
- double radius = 3 * base_factor;
- double degrees = Math.PI / 180.0;
- ctx.new_sub_path();
- ctx.arc(width - radius, radius, radius, -90 * degrees, 0 * degrees);
- ctx.arc(width - radius, height - radius, radius, 0 * degrees, 90 * degrees);
- ctx.arc(radius, height - radius, radius, 90 * degrees, 180 * degrees);
- ctx.arc(radius, radius, radius, 180 * degrees, 270 * degrees);
- ctx.close_path();
- ctx.clip();
-
- if (text_only != null) {
- ctx.set_source_surface(sub_surface(ctx, -1, width, height, base_factor), 0, 0);
- ctx.paint();
- } else if (current_jids.length == 4 || with_plus) {
- Cairo.Surface buffer = new Cairo.Surface.similar(ctx.get_target(), Cairo.Content.COLOR_ALPHA, width, height);
- Cairo.Context bufctx = new Cairo.Context(buffer);
- bufctx.scale(0.5, 0.5);
- bufctx.set_source_surface(sub_surface(ctx, 0, width - 1, height - 1, 2 * base_factor), 0, 0);
- bufctx.paint();
- bufctx.set_source_surface(sub_surface(ctx, 1, width - 1, height - 1, 2 * base_factor), width + 1, 0);
- bufctx.paint();
- bufctx.set_source_surface(sub_surface(ctx, 2, width - 1, height - 1, 2 * base_factor), 0, height + 1);
- bufctx.paint();
- if (with_plus) {
- bufctx.set_source_surface(sub_surface(ctx, -1, width - 1, height - 1, 2 * base_factor), width + 1, height + 1);
- bufctx.paint();
- } else {
- bufctx.set_source_surface(sub_surface(ctx, 3, width - 1, height - 1, 2 * base_factor), width + 1, height + 1);
- bufctx.paint();
- }
-
- ctx.set_source_surface(buffer, 0, 0);
- ctx.paint();
- } else if (current_jids.length == 3) {
- Cairo.Surface buffer = new Cairo.Surface.similar(ctx.get_target(), Cairo.Content.COLOR_ALPHA, width, height);
- Cairo.Context bufctx = new Cairo.Context(buffer);
- bufctx.scale(0.5, 0.5);
- bufctx.set_source_surface(sub_surface(ctx, 0, width - 1, height - 1, 2 * base_factor), 0, 0);
- bufctx.paint();
- bufctx.set_source_surface(sub_surface(ctx, 1, width - 1, height * 2, 2 * base_factor), width + 1, 0);
- bufctx.paint();
- bufctx.set_source_surface(sub_surface(ctx, 2, width - 1 , height - 1, 2 * base_factor), 0, height + 1);
- bufctx.paint();
-
- ctx.set_source_surface(buffer, 0, 0);
- ctx.paint();
- } else if (current_jids.length == 2) {
- Cairo.Surface buffer = new Cairo.Surface.similar(ctx.get_target(), Cairo.Content.COLOR_ALPHA, width, height);
- Cairo.Context bufctx = new Cairo.Context(buffer);
- bufctx.scale(0.5, 0.5);
- bufctx.set_source_surface(sub_surface(ctx, 0, width - 1, height * 2, 2 * base_factor), 0, 0);
- bufctx.paint();
- bufctx.set_source_surface(sub_surface(ctx, 1, width - 1, height * 2, 2 * base_factor), width + 1, 0);
- bufctx.paint();
-
- ctx.set_source_surface(buffer, 0, 0);
- ctx.paint();
- } else if (current_jids.length == 1) {
- ctx.set_source_surface(sub_surface(ctx, 0, width, height, base_factor), 0, 0);
- ctx.paint();
- } else {
- assert_not_reached();
- }
-
- if (gray) {
- // convert to greyscale
- ctx.set_operator(Cairo.Operator.HSL_COLOR);
- ctx.set_source_rgb(1, 1, 1);
- ctx.rectangle(0, 0, width, height);
- ctx.fill();
- // make the visible part more light
- ctx.set_operator(Cairo.Operator.ATOP);
- ctx.set_source_rgba(1, 1, 1, 0.7);
- ctx.rectangle(0, 0, width, height);
- ctx.fill();
- }
+ drawer.size(height, width)
+ .scale(base_factor)
+ .font(get_pango_context().get_font_description().get_family())
+ .draw_on_context(ctx);
if (use_image_surface == 1) {
ctx_in.set_source_surface(ctx.get_target(), 0, 0);
@@ -190,100 +73,38 @@ public class AvatarImage : Misc {
}
public override void destroy() {
+ disconnect_stream_interactor();
+ }
+
+ private void disconnect_stream_interactor() {
if (stream_interactor != null) {
- stream_interactor.get_module(PresenceManager.IDENTITY).show_received.disconnect(on_show_received);
- stream_interactor.get_module(AvatarManager.IDENTITY).received_avatar.disconnect(on_received_avatar);
+ presence_manager.show_received.disconnect(on_show_received);
+ avatar_manager.received_avatar.disconnect(on_received_avatar);
stream_interactor.connection_manager.connection_state_changed.disconnect(on_connection_changed);
stream_interactor.get_module(RosterManager.IDENTITY).updated_roster_item.disconnect(on_roster_updated);
- stream_interactor.get_module(MucManager.IDENTITY).private_room_occupant_updated.disconnect(on_occupant_updated);
- }
- }
-
- public void set_jid(StreamInteractor stream_interactor, Jid jid_, Account account, bool force_update = false) {
- this.account = account;
- if (this.stream_interactor == null) {
- this.stream_interactor = stream_interactor;
- stream_interactor.get_module(PresenceManager.IDENTITY).show_received.connect(on_show_received);
- stream_interactor.get_module(AvatarManager.IDENTITY).received_avatar.connect(on_received_avatar);
- stream_interactor.connection_manager.connection_state_changed.connect(on_connection_changed);
- stream_interactor.get_module(RosterManager.IDENTITY).updated_roster_item.connect(on_roster_updated);
- stream_interactor.get_module(MucManager.IDENTITY).private_room_occupant_updated.connect(on_occupant_updated);
- }
- if (muc_manager.is_groupchat(jid_, account) && !avatar_manager.has_avatar(account, jid_)) {
- // Groupchat without avatar
- Gee.List<Jid>? occupants;
- if (muc_manager.is_private_room(account, jid_)) {
- occupants = muc_manager.get_other_offline_members(jid_, account);
- } else {
- occupants = muc_manager.get_other_occupants(jid_, account);
- }
- jid = jid_;
- if (occupants == null || occupants.size == 0) {
- if (force_update || current_jids.length != 1 || !current_jids[0].equals(jid_) || gray != (allow_gray && (occupants == null || !is_self_online()))) {
- set_jids_(new Jid[] {jid_}, false, occupants == null || !is_self_online());
- }
- } else if (occupants.size > 4) {
- bool requires_update = force_update;
- if (!with_plus) requires_update = true;
- foreach (Jid jid in current_jids) {
- if (!occupants.contains(jid)) {
- requires_update = true;
- }
- }
- if (requires_update) {
- set_jids_(occupants.slice(0, 3).to_array(), true);
- }
- } else { // 1 <= occupants.size <= 4
- bool requires_update = force_update;
- if (with_plus) requires_update = true;
- if (current_jids.length != occupants.size) requires_update = true;
- foreach (Jid jid in current_jids) {
- if (!occupants.contains(jid)) {
- requires_update = true;
- }
- }
- if (requires_update) {
- set_jids_(occupants.to_array(), false);
- }
- }
- } else {
- // Single user or MUC with vcard avatar
- this.jid = jid_;
- if (force_update || current_jids.length != 1 || !current_jids[0].equals(jid) || gray != (allow_gray && (!is_counterpart_online(jid) || !is_self_online()))) {
- set_jids_(new Jid[] { jid }, false, !is_counterpart_online(jid) || !is_self_online());
- }
+ muc_manager.private_room_occupant_updated.disconnect(on_private_room_occupant_updated);
+ stream_interactor = null;
}
}
- public void set_jids(StreamInteractor stream_interactor, Jid[] jids, Account account, bool gray = false) {
- this.stream_interactor = stream_interactor;
- this.account = account;
- set_jids_(jids.length > 3 ? jids[0:3] : jids, jids.length > 3, gray);
- }
-
private void on_show_received(Show show, Jid jid, Account account) {
if (!account.equals(this.account)) return;
- if (jid.equals_bare(this.jid)) {
- set_jid(stream_interactor, this.jid, account, true);
- return;
- }
- foreach (Jid jid_ in current_jids) {
- if (jid.equals_bare(jid_)) {
- set_jid(stream_interactor, this.jid, account, true);
- return;
- }
- }
+ update_avatar_if_jid(jid);
}
private void on_received_avatar(Gdk.Pixbuf avatar, Jid jid, Account account) {
if (!account.equals(this.account)) return;
- if (jid.equals_bare(this.jid)) {
- set_jid(stream_interactor, this.jid, account, true);
+ update_avatar_if_jid(jid);
+ }
+
+ private void update_avatar_if_jid(Jid jid) {
+ if (jid.equals_bare(this.conversation.counterpart)) {
+ update_avatar_async.begin();
return;
}
- foreach (Jid jid_ in current_jids) {
- if (jid.equals_bare(jid_)) {
- set_jid(stream_interactor, this.jid, account, true);
+ foreach (Jid ours in this.jids) {
+ if (jid.equals_bare(ours)) {
+ update_avatar_async.begin();
return;
}
}
@@ -291,67 +112,73 @@ public class AvatarImage : Misc {
private void on_connection_changed(Account account, ConnectionManager.ConnectionState state) {
if (!account.equals(this.account)) return;
- set_jid(stream_interactor, this.jid, account, true);
+ update_avatar_async.begin();
}
private void on_roster_updated(Account account, Jid jid, Roster.Item roster_item) {
if (!account.equals(this.account)) return;
- if (!jid.equals_bare(this.jid)) return;
- set_jid(stream_interactor, this.jid, account, true);
+ update_avatar_if_jid(jid);
}
- private void on_occupant_updated(Account account, Jid room, Jid occupant) {
+ private void on_private_room_occupant_updated(Account account, Jid room, Jid occupant) {
if (!account.equals(this.account)) return;
- if (!room.equals_bare(this.jid)) return;
- set_jid(stream_interactor, this.jid, account, true);
+ update_avatar_if_jid(room);
}
private bool is_self_online() {
- return stream_interactor.connection_manager.get_state(account) == ConnectionManager.ConnectionState.CONNECTED;
+ if (connection_manager != null) {
+ return connection_manager.get_state(account) == ConnectionManager.ConnectionState.CONNECTED;
+ }
+ return false;
+ }
+
+ private bool is_counterpart_online() {
+ return presence_manager.get_full_jids(conversation.counterpart, account) != null;
}
- private bool is_counterpart_online(Jid counterpart) {
- return stream_interactor.get_module(PresenceManager.IDENTITY).get_full_jids(counterpart, account) != null;
+ public void set_conversation(StreamInteractor stream_interactor, Conversation conversation) {
+ set_avatar_async.begin(stream_interactor, conversation, new Jid[0]);
}
- public void set_jids_(Jid[] jids, bool with_plus = false, bool gray = false) {
- assert(jids.length > 0);
- assert(jids.length < 5);
- assert(!with_plus || jids.length == 3);
+ public void set_conversation_participant(StreamInteractor stream_interactor, Conversation conversation, Jid sub_jid) {
+ set_avatar_async.begin(stream_interactor, conversation, new Jid[] {sub_jid});
+ }
+
+ public void set_conversation_participants(StreamInteractor stream_interactor, Conversation conversation, Jid[] sub_jids) {
+ set_avatar_async.begin(stream_interactor, conversation, sub_jids);
+ }
+
+ private async void update_avatar_async() {
this.cached_surface = null;
- this.text_only = null;
- this.gray = gray && allow_gray;
- this.with_plus = with_plus;
+ this.drawer = yield Util.get_conversation_participants_avatar_drawer(stream_interactor, conversation, jids);
+ if (allow_gray && (!is_self_online() || !is_counterpart_online())) drawer.grayscale();
- set_jids_async.begin(jids);
+ queue_draw();
}
- public async void set_jids_async(Jid[] jids) {
- Jid[] jids_ = jids;
- Gdk.Pixbuf[] avatars = new Gdk.Pixbuf[jids.length];
- for (int i = 0; i < jids_.length; ++i) {
- Jid? real_jid = muc_manager.get_real_jid(jids_[i], account);
- if (real_jid != null) {
- avatars[i] = yield avatar_manager.get_avatar(account, real_jid);
- if (avatars[i] != null) {
- jids_[i] = real_jid;
- continue;
- }
- }
- avatars[i] = yield avatar_manager.get_avatar(account, jids_[i]);
+ private async void set_avatar_async(StreamInteractor stream_interactor, Conversation conversation, Jid[] jids) {
+ if (this.stream_interactor != null && stream_interactor != this.stream_interactor) {
+ disconnect_stream_interactor();
}
- this.current_avatars = avatars;
- this.current_jids = jids_;
+ if (this.stream_interactor != stream_interactor) {
+ this.stream_interactor = stream_interactor;
+ presence_manager.show_received.connect(on_show_received);
+ stream_interactor.get_module(AvatarManager.IDENTITY).received_avatar.connect(on_received_avatar);
+ stream_interactor.connection_manager.connection_state_changed.connect(on_connection_changed);
+ stream_interactor.get_module(RosterManager.IDENTITY).updated_roster_item.connect(on_roster_updated);
+ muc_manager.private_room_occupant_updated.connect(on_private_room_occupant_updated);
+ }
+ this.cached_surface = null;
+ this.conversation = conversation;
+ this.jids = jids;
- queue_draw();
+ yield update_avatar_async();
}
public void set_text(string text, bool gray = true) {
- this.text_only = text;
- this.gray = gray;
- this.with_plus = false;
- this.current_jids = null;
- this.current_avatars = null;
+ disconnect_stream_interactor();
+ this.drawer = new AvatarDrawer().tile(null, text, null);
+ if (gray) drawer.grayscale();
queue_draw();
}
}