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
4 changes: 3 additions & 1 deletion src/Views/Wallpaper.vala
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,9 @@ public class PantheonShell.Wallpaper : Switchboard.SettingsPage {
return;
}

var wallpaper = new WallpaperContainer (uri);
var wallpaper = new WallpaperContainer () {
uri = uri
};
wallpaper_model.insert_sorted (wallpaper, wallpapers_sort_function);

wallpaper.trash.connect (() => {
Expand Down
175 changes: 129 additions & 46 deletions src/Widgets/WallpaperContainer.vala
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,24 @@
public class PantheonShell.WallpaperContainer : Granite.Bin {
public signal void trash ();

// https://www.w3.org/WAI/WCAG21/Understanding/target-size.html
private const int TOUCH_TARGET_WIDTH = 44;

protected const int THUMB_WIDTH = 256;
protected const int THUMB_HEIGHT = 144;
protected Gtk.Picture image;

private GLib.Menu menu_model;
private GLib.SimpleAction remove_wallpaper_action;
private Gtk.Revealer check_revealer;

private Gtk.EventControllerKey menu_key_controller;
private Gtk.GestureClick? click_controller;
private Gtk.GestureLongPress? long_press_controller;
private Gtk.PopoverMenu? context_menu;
private string? thumb_path = null;

public string? uri { get; construct; default = null; }
public string? uri { get; set; default = null; }
public uint64 creation_date = 0;

public bool checked {
Expand All @@ -48,10 +57,6 @@ public class PantheonShell.WallpaperContainer : Granite.Bin {
}
}

public WallpaperContainer (string uri) {
Object (uri: uri);
}

construct {
image = new Gtk.Picture () {
content_fit = COVER,
Expand Down Expand Up @@ -80,58 +85,136 @@ public class PantheonShell.WallpaperContainer : Granite.Bin {
halign = CENTER;
valign = CENTER;

// So we can receive key events
focusable = true;
child = overlay;

if (uri != null) {
var remove_wallpaper_action = new SimpleAction ("trash", null);
remove_wallpaper_action.activate.connect (() => trash ());
remove_wallpaper_action = new SimpleAction ("trash", null);
remove_wallpaper_action.activate.connect (() => trash ());

var action_group = new SimpleActionGroup ();
action_group.add_action (remove_wallpaper_action);
var action_group = new SimpleActionGroup ();
action_group.add_action (remove_wallpaper_action);

insert_action_group ("wallpaper", action_group);
insert_action_group ("wallpaper", action_group);

var file = File.new_for_uri (uri);
try {
var info = file.query_info ("*", FileQueryInfoFlags.NONE);
menu_model = new Menu ();
menu_model.append (_("Remove"), "wallpaper.trash");

thumb_path = info.get_attribute_as_string (FileAttribute.THUMBNAIL_PATH);
notify["uri"].connect (construct_from_uri);
}

if (thumb_path != null && info.get_attribute_boolean (FileAttribute.THUMBNAIL_IS_VALID)) {
update_thumb.begin ();
} else {
generate_and_load_thumb ();
}
private void construct_from_uri () {
if (uri == null) {
remove_controller (click_controller);
remove_controller (long_press_controller);
remove_controller (menu_key_controller);

creation_date = info.get_attribute_uint64 (GLib.FileAttribute.TIME_CREATED);
remove_wallpaper_action.set_enabled (info.get_attribute_boolean (GLib.FileAttribute.ACCESS_CAN_DELETE));
} catch (Error e) {
critical (e.message);
click_controller = null;
long_press_controller = null;
menu_key_controller = null;

context_menu.unparent ();
context_menu = null;

return;
}

var file = File.new_for_uri (uri);
try {
var info = file.query_info ("*", FileQueryInfoFlags.NONE);

thumb_path = info.get_attribute_as_string (FileAttribute.THUMBNAIL_PATH);

if (thumb_path != null && info.get_attribute_boolean (FileAttribute.THUMBNAIL_IS_VALID)) {
update_thumb.begin ();
} else {
generate_and_load_thumb ();
}

var menu_model = new Menu ();
menu_model.append (_("Remove"), "wallpaper.trash");

var context_menu = new Gtk.PopoverMenu.from_model (menu_model) {
halign = START,
has_arrow = false
};
context_menu.set_parent (this);

var secondary_click_gesture = new Gtk.GestureClick () {
button = Gdk.BUTTON_SECONDARY
};
secondary_click_gesture.released.connect ((n_press, x, y) => {
secondary_click_gesture.set_state (CLAIMED);
context_menu.pointing_to = Gdk.Rectangle () {
x = (int) x,
y = (int) y
};
context_menu.popup ();
});

add_controller (secondary_click_gesture);
creation_date = info.get_attribute_uint64 (GLib.FileAttribute.TIME_CREATED);
remove_wallpaper_action.set_enabled (info.get_attribute_boolean (GLib.FileAttribute.ACCESS_CAN_DELETE));
} catch (Error e) {
critical (e.message);
}

context_menu = new Gtk.PopoverMenu.from_model (menu_model) {
halign = START,
has_arrow = false
};
context_menu.set_parent (this);

click_controller = new Gtk.GestureClick () {
button = 0,
exclusive = true
};
click_controller.pressed.connect ((n_press, x, y) => {
var sequence = click_controller.get_current_sequence ();
var event = click_controller.get_last_event (sequence);

if (event.triggers_context_menu ()) {
context_menu.halign = START;
menu_popup_at_pointer (context_menu, x, y);

click_controller.set_state (CLAIMED);
click_controller.reset ();
}
});

long_press_controller = new Gtk.GestureLongPress () {
touch_only = true
};
long_press_controller.pressed.connect ((x, y) => {
// Try to keep menu from under your hand
if (x > get_root ().get_width () / 2) {
context_menu.halign = END;
x -= TOUCH_TARGET_WIDTH;
} else {
context_menu.halign = START;
x += TOUCH_TARGET_WIDTH;
}

menu_popup_at_pointer (context_menu, x, y - (TOUCH_TARGET_WIDTH * 0.75));
});

menu_key_controller = new Gtk.EventControllerKey ();
menu_key_controller.key_released.connect ((keyval, keycode, state) => {
var mods = state & Gtk.accelerator_get_default_mod_mask ();
switch (keyval) {
case Gdk.Key.F10:
if (mods == Gdk.ModifierType.SHIFT_MASK) {
menu_popup_on_keypress (context_menu);
}
break;
case Gdk.Key.Menu:
case Gdk.Key.MenuKB:
menu_popup_on_keypress (context_menu);
break;
default:
return;
}
});

add_controller (click_controller);
add_controller (long_press_controller);
add_controller (menu_key_controller);
}

private void menu_popup_on_keypress (Gtk.PopoverMenu popover) {
popover.halign = END;
popover.set_pointing_to (Gdk.Rectangle () {
x = (int) get_width (),
y = (int) get_height () / 2
});
popover.popup ();
}

private void menu_popup_at_pointer (Gtk.PopoverMenu popover, double x, double y) {
var rect = Gdk.Rectangle () {
x = (int) x,
y = (int) y
};
popover.pointing_to = rect;
popover.popup ();
}

private void generate_and_load_thumb () {
Expand Down