Skip to content
Closed
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
2 changes: 2 additions & 0 deletions src/AppSystem/Launcher.vala
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,8 @@ public class Dock.Launcher : BaseItem {
bounce_down = null;
bounce_up = null;
shake = null;
badge_fade = null;
badge_scale = null;
current_count_binding.unbind ();
remove_dnd_cycle ();
}
Expand Down
73 changes: 44 additions & 29 deletions src/ItemGroup.vala
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
*/

public class Dock.ItemGroup : Gtk.Fixed {
private const string OBJECT_DATA_KEY = "item-group-obj";

[CCode (has_target = false)]
public delegate BaseItem CreateBaseItemFunc (Object obj);

Expand All @@ -23,8 +21,11 @@

private bool relayout_queued = false;

private HashTable<Object, BaseItem> cached_items;
private uint clear_cache_id = 0;
private HashTable<Object, BaseItem> obj_to_item_table = new HashTable<Object, BaseItem> (null, null);
private HashTable<BaseItem, Object> item_to_obj_table = new HashTable<BaseItem, Object> (null, null);

private GenericSet<BaseItem> items_marked_for_removal = new GenericSet<BaseItem> (null, null);
private uint remove_items_id = 0;

public ItemGroup (ListModel items, CreateBaseItemFunc create_item_func) {
Object (items: items, create_item_func: create_item_func);
Expand All @@ -51,8 +52,6 @@
on_items_changed (0, 0, items.get_n_items ());

overflow = VISIBLE;

cached_items = new HashTable<Object, BaseItem> (null, null);
}

private void queue_relayout () {
Expand Down Expand Up @@ -101,41 +100,64 @@
private void on_items_changed (uint position, uint removed, uint added) {
var start_iter = item_store.get_iter_at_pos ((int) position);
var end_iter = start_iter.move ((int) removed);
start_iter.foreach_range (end_iter, cache_item);
start_iter.foreach_range (end_iter, remove_item);
start_iter.foreach_range (end_iter, mark_item_for_removal);
start_iter.remove_range (end_iter);

var insert_iter = item_store.get_iter_at_pos ((int) position);
for (int i = (int) position; i < position + added; i++) {
var item = get_or_create_item (items.get_item (i));
insert_iter.insert_before (item);

unmark_item_for_removal (item);
add_item (i, item);
}
}

// Make sure that if an item is removed and added again in the same
// mainloop iteration it gets mapped to the same BaseItem
private void cache_item (BaseItem item) {
cached_items[item.get_data<Object> (OBJECT_DATA_KEY)] = item;
/*
* During drag-and-drop we get 2 separate item_changed signals:
* 1 for removing the dragged item, and 1 for adding it back into new place.
* To avoid removing this item, we remove it in Idle.
*/
private void mark_item_for_removal (BaseItem item) {
items_marked_for_removal.add (item);

item.revealed_done.connect (remove_item);
item.set_revealed (false);

if (remove_items_id == 0) {
remove_items_id = Idle.add_once (remove_pending_items);
}
}

private void remove_pending_items () {
remove_items_id = 0;

foreach (var item in items_marked_for_removal.get_values ()) {
item.cleanup ();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a huge fan of calling it here because the animation is still running and the item won't be disposed. Currently that's not a problem but it means we have to be more careful later about what we can and can't do. I would prefer it being called when the item then actually gets disposed.

However in general I think the best solution would be to avoid having a cleanup alltogether by having the animation targets act on a child widget and not on the baseitem itself, always using static functions for callbacks, etc. instead of stuffing more things in the cleanup method. I think we should work towards that.

items_marked_for_removal.remove (item);

if (clear_cache_id == 0) {
clear_cache_id = Idle.add_once (clear_cache);
var obj = item_to_obj_table[item];
obj_to_item_table.remove (obj);
item_to_obj_table.remove (item);
}
}

private void clear_cache () {
cached_items.remove_all ();
clear_cache_id = 0;
private void unmark_item_for_removal (BaseItem item) {
items_marked_for_removal.remove (item);

item.revealed_done.disconnect (remove_item);
item.set_revealed (true);

}

private BaseItem get_or_create_item (Object obj) {
if (obj in cached_items) {
return cached_items[obj];
if (obj in obj_to_item_table) {
return obj_to_item_table[obj];
}

var base_item = create_item_func (obj);
base_item.set_data<Object> (OBJECT_DATA_KEY, obj);
obj_to_item_table[obj] = base_item;
item_to_obj_table[base_item] = obj;
return base_item;
}

Expand All @@ -144,7 +166,7 @@
// The item was already in this group and is currently being removed
// so immediately finish the removal and add it as if it was new
// This happens when the items are repositioned via dnd
finish_remove (item);
remove_item (item);
}

item.visible = false;
Expand All @@ -157,14 +179,7 @@
}

private void remove_item (BaseItem item) {
item.revealed_done.connect (finish_remove);
item.set_revealed (false);

cached_items[item.get_data<Object> ("dock-obj")] = item;
}

private void finish_remove (BaseItem item) {
item.revealed_done.disconnect (finish_remove);
item.revealed_done.disconnect (remove_item);

remove (item);

Expand Down