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
11 changes: 8 additions & 3 deletions data/gschema.xml
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<schemalist>
<schema path="/io/github/ellie_commons/indicator-clipboard/" id="io.github.ellie_commons.indicator-clipboard">
<key name="visible" type="b">
<key name="always-hide" type="b">
<default>false</default>
<summary>Whether indicator is hidden and inactive</summary>
<description>Always hide indicator if set to true. While hidden the indicator does not monitor the clipboard.</description>
</key>
<key name="active" type="b">
<default>true</default>
<summary>Whether indicator is visible</summary>
<description>Hide indicator if set to false. It is still running, just hidden</description>
<summary>Whether indicator is active</summary>
<description>Whether the indicator is monitoring and recording the clipboard contents</description>
</key>
</schema>
</schemalist>
95 changes: 74 additions & 21 deletions src/HistoryWidget.vala
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,63 @@
*/

public class Clipboard.HistoryWidget : Gtk.Box {
private const string ACTIVE_DESCRIPTION = N_("Monitoring the clipboard contents");
private const string PRIVACY_DESCRIPTION = N_("Privacy Mode is On");

private Gee.HashSet<string> clipboard_text_set;
private Gtk.ListBox clipboard_item_list;
private string last_text = "";
private uint wait_timeout = 0;
private Granite.SwitchModelButton active_switch;
private Gtk.Box privacy_widget;
private Gtk.ScrolledWindow scroll_box;
private Gtk.Stack stack;
private unowned Gtk.Clipboard clipboard;

public signal void close_request ();

construct {
orientation = VERTICAL;
spacing = 6;

active_switch = new Granite.SwitchModelButton (_("Clipboard Manager")) {
description = _(ACTIVE_DESCRIPTION)
};

var inactive_header_label = new Granite.HeaderLabel (_("The ClipboardManager is disabled"));
var inactive_subheader_label = new Gtk.Label ("") {
label = Granite.TOOLTIP_SECONDARY_TEXT_MARKUP.printf (_("History is off in the Privacy and Security settings")),
use_markup = true
};
privacy_widget = new Gtk.Box (VERTICAL, 0) {
margin_start = 6,
margin_end = 6
};
privacy_widget.add (inactive_header_label);
privacy_widget.add (inactive_subheader_label);

Clipboard.Indicator.settings.bind ("active", active_switch, "active", DEFAULT);

clipboard_text_set = new Gee.HashSet<string> ();

clipboard_item_list = new Gtk.ListBox () {
selection_mode = SINGLE
};
clipboard_item_list.set_placeholder (new Gtk.Label (_("Clipboard Empty")));
var scroll_box = new Gtk.ScrolledWindow (null, null);

scroll_box = new Gtk.ScrolledWindow (null, null);
scroll_box.max_content_height = 512;
scroll_box.propagate_natural_height = true;
scroll_box.hscrollbar_policy = Gtk.PolicyType.NEVER;
scroll_box.add (clipboard_item_list);

add (scroll_box);
stack = new Gtk.Stack ();
stack.add_named (scroll_box, "clipboard");
stack.add_named (privacy_widget, "privacy");

add (active_switch);
add (stack);

show_all ();

clipboard_item_list.row_activated.connect ((row) => {
Expand All @@ -33,6 +69,8 @@ public class Clipboard.HistoryWidget : Gtk.Box {
clipboard.set_text (text, -1);
close_request ();
});

clipboard = Gtk.Clipboard.get_default (Gdk.Display.get_default ());
}

~HistoryWidget () {
Expand All @@ -41,28 +79,43 @@ public class Clipboard.HistoryWidget : Gtk.Box {

// No notifications from clipboard? So poll it periodically for new text
public void wait_for_text () {
var clipboard = Gtk.Clipboard.get_default (Gdk.Display.get_default ());
wait_timeout = Timeout.add_full (Priority.LOW, 1000, () => {
if (clipboard.wait_is_text_available ()) {
clipboard.request_text ((cb, text) => {
if (text != last_text && !clipboard_text_set.contains (text)) {
last_text = text;
clipboard_text_set.add (text);
var new_item = new ItemRow (text);
clipboard_item_list.prepend (new_item);
clipboard_item_list.select_row (new_item);
clipboard_item_list.show_all ();
}
});
}

return Source.CONTINUE;
clipboard.owner_change.connect (on_clipboard_owner_change);
}

private void on_clipboard_owner_change () requires (clipboard != null) {
if (clipboard.wait_is_text_available ()) {
clipboard.request_text ((cb, text) => {
if (!clipboard_text_set.contains (text)) {
clipboard_text_set.add (text);
var new_item = new ItemRow (text);
clipboard_item_list.prepend (new_item);
clipboard_item_list.select_row (new_item);
}
});
}
}

public void stop_waiting_for_text () requires (clipboard != null) {
clipboard.owner_change.disconnect (on_clipboard_owner_change);
}

public void clear_history () {
clipboard_text_set.clear ();
clipboard_item_list.@foreach ((child) => {
child.destroy ();
});
}

public void stop_waiting_for_text () {
if (wait_timeout > 0) {
Source.remove (wait_timeout);
public void set_privacy_mode (bool privacy_on) {
active_switch.sensitive = !privacy_on;
stack.visible_child_name = privacy_on ? "privacy" : "clipboard";
if (privacy_on) {
stop_waiting_for_text ();
clear_history ();
active_switch.description = _(PRIVACY_DESCRIPTION);
} else {
wait_for_text ();
active_switch.description = _(ACTIVE_DESCRIPTION);
}
}

Expand Down
56 changes: 44 additions & 12 deletions src/Indicator.vala
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,17 @@
*/

public class Clipboard.Indicator : Wingpanel.Indicator {
private static GLib.Settings settings;
public static GLib.Settings settings;
private static GLib.Settings gnome_privacy_settings;
private const string NORMAL_ICON_NAME = "edit-copy-symbolic";
private const string STOPPED_ICON_NAME = "task-past-due-symbolic";
private Gtk.Image panel_icon;
private HistoryWidget history_widget;

public bool always_hide { get; set; }
public bool active { get; set; }
public bool privacy_on { get; set; }

public Wingpanel.IndicatorManager.ServerType server_type { get; construct set; }

public Indicator (Wingpanel.IndicatorManager.ServerType indicator_server_type) {
Expand All @@ -21,45 +28,70 @@ public class Clipboard.Indicator : Wingpanel.Indicator {
Intl.bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
Intl.textdomain (GETTEXT_PACKAGE);

visible = true;

settings = new GLib.Settings ("io.github.ellie_commons.indicator-clipboard");
settings.bind ("visible", this, "visible", GLib.SettingsBindFlags.DEFAULT);
settings.bind ("always-hide", this, "always-hide", DEFAULT);
settings.bind ("active", this, "active", DEFAULT);


// Ensure correct appearance before showing
get_display_widget ();
get_widget ();
update_appearance ();
}


public override Gtk.Widget get_display_widget () {
if (panel_icon == null) {
panel_icon = new Gtk.Image.from_icon_name ("edit-copy-symbolic", Gtk.IconSize.SMALL_TOOLBAR);
panel_icon = new Gtk.Image.from_icon_name (NORMAL_ICON_NAME, Gtk.IconSize.SMALL_TOOLBAR);

if (server_type == Wingpanel.IndicatorManager.ServerType.GREETER) {
this.visible = false;
} else {
// var visible_settings = new Settings ("io.elementary.desktop.wingpanel.clipboard");
// visible_settings.bind ("show-indicator", this, "visible", SettingsBindFlags.DEFAULT);
this.visible = true;
gnome_privacy_settings = new Settings ("org.gnome.desktop.privacy");
gnome_privacy_settings.bind ("remember-recent-files", this, "privacy-on", DEFAULT | INVERT_BOOLEAN);
}
}

get_widget ();
return panel_icon;
}

public override Gtk.Widget? get_widget () {
if (history_widget == null &&
server_type == Wingpanel.IndicatorManager.ServerType.SESSION) {
history_widget = new HistoryWidget ();
history_widget.close_request.connect (() => {
close ();
});
history_widget.wait_for_text ();

history_widget = new HistoryWidget ();
history_widget.close_request.connect (() => {
close ();
});

this.notify["privacy-on"].connect (update_appearance);
this.notify["always-hide"].connect (update_appearance);
this.notify["active"].connect (update_appearance);
update_appearance ();
}

return history_widget;
}

public override void opened () {

}

public override void closed () {
}

private void update_appearance () {
if (!active || privacy_on || always_hide) {
panel_icon.icon_name = STOPPED_ICON_NAME;
} else if (active && !privacy_on && !always_hide) {
panel_icon.icon_name = NORMAL_ICON_NAME;
}

visible = !always_hide;
history_widget.set_privacy_mode (privacy_on);
}
}

public Wingpanel.Indicator? get_indicator (Module module, Wingpanel.IndicatorManager.ServerType server_type) {
Expand Down