Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions libdiodon/clipboard-item.vala
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,13 @@ namespace Diodon
*/
public abstract Gtk.Image? get_image();

/**
* preview pixbuf for tooltip display
*
* @return scaled preview pixbuf or null if not available
*/
public abstract Gdk.Pixbuf? get_preview_pixbuf();

/**
* icon to represent type of clipboard item
*
Expand Down
83 changes: 83 additions & 0 deletions libdiodon/clipboard-menu-item.vala
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ namespace Diodon
class ClipboardMenuItem : Gtk.ImageMenuItem
{
private string _checksum;
private IClipboardItem _item;
private Gdk.Pixbuf? _cached_preview;
private bool _preview_loaded;
private static Gtk.Window? _preview_window;

/**
* Clipboard item constructor
Expand All @@ -37,6 +41,7 @@ namespace Diodon
public ClipboardMenuItem(IClipboardItem item)
{
_checksum = item.get_checksum();
_item = item;
set_label(item.get_label());

// check if image needs to be shown
Expand All @@ -45,6 +50,84 @@ namespace Diodon
set_image(image);
set_always_show_image(true);
}

debug("ClipboardMenuItem: connecting select/deselect for %s", _checksum);
select.connect(on_item_select);
deselect.connect(on_item_deselect);
}

private Gdk.Pixbuf? get_preview()
{
if (!_preview_loaded) {
_cached_preview = _item.get_preview_pixbuf();
_preview_loaded = true;
}
return _cached_preview;
}

private void on_item_select()
{
debug("on_item_select: checksum=%s", _checksum);
Gdk.Pixbuf? preview = get_preview();
if (preview == null) {
debug("on_item_select: no preview available");
return;
}
debug("on_item_select: preview %dx%d", preview.width, preview.height);
if (_preview_window == null) {
_preview_window = new Gtk.Window(Gtk.WindowType.POPUP);
_preview_window.set_type_hint(Gdk.WindowTypeHint.TOOLTIP);
_preview_window.set_app_paintable(true);
Gdk.Screen screen = _preview_window.get_screen();
Gdk.Visual? visual = screen.get_rgba_visual();
if (visual != null) {
_preview_window.set_visual(visual);
}
}
_preview_window.foreach((child) => { _preview_window.remove(child); });
Gtk.Image preview_image = new Gtk.Image.from_pixbuf(preview);
Gtk.CssProvider css = new Gtk.CssProvider();
try {
css.load_from_data("frame { border: 1px solid #888888; }", -1);
} catch (Error e) {
warning("Failed to load preview CSS: %s", e.message);
}
Gtk.Frame frame = new Gtk.Frame(null);
frame.set_shadow_type(Gtk.ShadowType.NONE);
frame.get_style_context().add_provider(css, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION);
frame.add(preview_image);
_preview_window.add(frame);
_preview_window.resize(preview.width, preview.height);
Gdk.Display? display = Gdk.Display.get_default();
Gdk.Seat? seat = display != null ? display.get_default_seat() : null;
if (seat != null) {
int mouse_x, mouse_y;
seat.get_pointer().get_position(null, out mouse_x, out mouse_y);
int x = mouse_x + 16;
int y = mouse_y + 16;
Gdk.Screen screen = _preview_window.get_screen();
int screen_height = screen.get_height();
if (y + preview.height > screen_height) {
y = screen_height - preview.height;
}
if (y < 0) {
y = 0;
}
_preview_window.move(x, y);
}
_preview_window.show_all();
}

private static void on_item_deselect()
{
hide_preview();
}

public static void hide_preview()
{
if (_preview_window != null) {
_preview_window.hide();
}
}

/**
Expand Down
1 change: 1 addition & 0 deletions libdiodon/clipboard-menu.vala
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ namespace Diodon
show_all();

this.key_press_event.connect(on_key_pressed);
this.hide.connect(() => { ClipboardMenuItem.hide_preview(); });
}

/**
Expand Down
23 changes: 23 additions & 0 deletions libdiodon/file-clipboard-item.vala
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,29 @@ namespace Diodon
return image;
}

/**
* {@inheritDoc}
*/
public Gdk.Pixbuf? get_preview_pixbuf()
{
string[] paths = convert_to_paths(_paths);
if (paths.length == 0) {
return null;
}
string path = paths[0];
string mime_type = get_mime_type();
if (!mime_type.has_prefix("image/")) {
return null;
}
try {
Gdk.Pixbuf pixbuf = new Gdk.Pixbuf.from_file(path);
return ImageClipboardItem.create_preview_pixbuf(pixbuf);
} catch (Error e) {
warning("Could not load preview for file %s: %s", path, e.message);
return null;
}
}

/**
* {@inheritDoc}
*/
Expand Down
22 changes: 22 additions & 0 deletions libdiodon/image-clipboard-item.vala
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,14 @@ namespace Diodon
return new Gtk.Image.from_pixbuf(pixbuf_preview);
}

/**
* {@inheritDoc}
*/
public Gdk.Pixbuf? get_preview_pixbuf()
{
return create_preview_pixbuf(_pixbuf);
}

/**
* {@inheritDoc}
*/
Expand Down Expand Up @@ -224,6 +232,20 @@ namespace Diodon
*
* @param pixbuf scaled pixbuf
*/
public static Gdk.Pixbuf create_preview_pixbuf(Gdk.Pixbuf pixbuf)
{
int max_size = 500;
int width = pixbuf.width;
int height = pixbuf.height;
if (width <= max_size && height <= max_size) {
return pixbuf;
}
double scale = double.min((double) max_size / width, (double) max_size / height);
int new_width = (int) (width * scale);
int new_height = (int) (height * scale);
return pixbuf.scale_simple(new_width, new_height, Gdk.InterpType.BILINEAR);
}

private static Gdk.Pixbuf create_scaled_pixbuf(Gdk.Pixbuf pixbuf)
{
// get menu icon size
Expand Down
8 changes: 8 additions & 0 deletions libdiodon/text-clipboard-item.vala
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,14 @@ namespace Diodon
return null; // no image available for text content
}

/**
* {@inheritDoc}
*/
public Gdk.Pixbuf? get_preview_pixbuf()
{
return null;
}

/**
* {@inheritDoc}
*/
Expand Down