gtk: implement get_attachment_fd and texture/attachment cache, viewport loading
This commit is contained in:
@@ -13,30 +13,52 @@ private class SizeCache
|
||||
return instance;
|
||||
}
|
||||
|
||||
public Graphene.Size? get_size(string image_path) {
|
||||
return size_cache.get(image_path);
|
||||
public Graphene.Size? get_size(string attachment_guid) {
|
||||
return size_cache.get(attachment_guid);
|
||||
}
|
||||
|
||||
public void set_size(string image_path, Graphene.Size size) {
|
||||
size_cache.set(image_path, size);
|
||||
public void set_size(string attachment_guid, Graphene.Size size) {
|
||||
size_cache.set(attachment_guid, size);
|
||||
}
|
||||
}
|
||||
|
||||
private class TextureCache
|
||||
{
|
||||
private static TextureCache instance = null;
|
||||
private HashMap<string, Gdk.Texture> texture_cache = new HashMap<string, Gdk.Texture>();
|
||||
|
||||
public static TextureCache get_instance() {
|
||||
if (instance == null) {
|
||||
instance = new TextureCache();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public Gdk.Texture? get_texture(string attachment_guid) {
|
||||
return texture_cache.get(attachment_guid);
|
||||
}
|
||||
|
||||
public void set_texture(string attachment_guid, Gdk.Texture texture) {
|
||||
texture_cache.set(attachment_guid, texture);
|
||||
}
|
||||
}
|
||||
|
||||
private class ImageBubbleLayout : BubbleLayout
|
||||
{
|
||||
public string image_path;
|
||||
public string attachment_guid;
|
||||
public bool is_downloaded;
|
||||
public string? attachment_guid;
|
||||
|
||||
private Graphene.Size image_size;
|
||||
private Gdk.Texture? cached_texture = null;
|
||||
private bool preview_download_queued = false;
|
||||
|
||||
public ImageBubbleLayout(string image_path, bool from_me, Widget parent, float max_width, Graphene.Size? image_size = null) {
|
||||
public ImageBubbleLayout(string attachment_guid, bool from_me, Widget parent, float max_width, Graphene.Size? image_size = null) {
|
||||
base(parent, max_width);
|
||||
|
||||
this.from_me = from_me;
|
||||
this.image_path = image_path;
|
||||
this.attachment_guid = attachment_guid;
|
||||
this.is_downloaded = false;
|
||||
this.cached_texture = TextureCache.get_instance().get_texture(attachment_guid);
|
||||
|
||||
// Calculate image dimensions for layout
|
||||
calculate_image_dimensions(image_size);
|
||||
@@ -48,26 +70,25 @@ private class ImageBubbleLayout : BubbleLayout
|
||||
return;
|
||||
}
|
||||
|
||||
var cached_size = SizeCache.get_instance().get_size(image_path);
|
||||
var cached_size = SizeCache.get_instance().get_size(attachment_guid);
|
||||
if (cached_size != null) {
|
||||
this.image_size = cached_size;
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to load the image to get its dimensions
|
||||
this.image_size = Graphene.Size() { width = 200.0f, height = 150.0f };
|
||||
}
|
||||
|
||||
private void queue_preview_download_if_needed() {
|
||||
if (is_downloaded || preview_download_queued || attachment_guid == "") {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
warning("No image size provided, loading image to get dimensions");
|
||||
|
||||
var texture = Gdk.Texture.from_filename(image_path);
|
||||
var original_width = (float)texture.get_width();
|
||||
var original_height = (float)texture.get_height();
|
||||
|
||||
this.image_size = Graphene.Size() { width = original_width, height = original_height };
|
||||
SizeCache.get_instance().set_size(image_path, this.image_size);
|
||||
} catch (Error e) {
|
||||
// Fallback dimensions if image can't be loaded
|
||||
warning("Failed to load image %s: %s", image_path, e.message);
|
||||
this.image_size = Graphene.Size() { width = 200.0f, height = 150.0f };
|
||||
Repository.get_instance().download_attachment(attachment_guid, true);
|
||||
preview_download_queued = true;
|
||||
} catch (GLib.Error e) {
|
||||
warning("Failed to queue preview download for %s: %s", attachment_guid, e.message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,9 +102,22 @@ private class ImageBubbleLayout : BubbleLayout
|
||||
}
|
||||
|
||||
try {
|
||||
cached_texture = Gdk.Texture.from_filename(image_path);
|
||||
int fd = Repository.get_instance().open_attachment_fd(attachment_guid, true);
|
||||
var stream = new UnixInputStream(fd, true);
|
||||
var pixbuf = new Gdk.Pixbuf.from_stream(stream, null);
|
||||
cached_texture = Gdk.Texture.for_pixbuf(pixbuf);
|
||||
|
||||
if (cached_texture != null) {
|
||||
TextureCache.get_instance().set_texture(attachment_guid, cached_texture);
|
||||
this.image_size = Graphene.Size() {
|
||||
width = (float)cached_texture.get_width(),
|
||||
height = (float)cached_texture.get_height()
|
||||
};
|
||||
SizeCache.get_instance().set_size(attachment_guid, this.image_size);
|
||||
parent.queue_allocate();
|
||||
}
|
||||
} catch (Error e) {
|
||||
warning("Failed to load image %s: %s", image_path, e.message);
|
||||
warning("Failed to load preview image for %s: %s", attachment_guid, e.message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,6 +144,7 @@ private class ImageBubbleLayout : BubbleLayout
|
||||
}
|
||||
|
||||
public override void draw_content(Snapshot snapshot) {
|
||||
queue_preview_download_if_needed();
|
||||
load_image_if_needed();
|
||||
|
||||
snapshot.save();
|
||||
@@ -137,4 +172,4 @@ private class ImageBubbleLayout : BubbleLayout
|
||||
public override void copy(Gdk.Clipboard clipboard) {
|
||||
clipboard.set_texture(cached_texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user